4300. 【NOIP2015模拟11.3】装饰大楼

Description

国际信息学奥林匹克竞赛将要在日本召开了。为了欢迎全世界的选手们,委员会决定将从机场到宿舍沿路的大楼装饰起来。根据某著名设计师的设计,做装饰的大楼从机场到宿舍的方向必须高度严格递增。也就是说,如果做装饰的大楼从机场开始高度顺次为h1,h2,h3,...,那么必须满足h1<h2<h3<...。
为了使尽量多的装饰品发挥光泽,做装饰的大楼希望越多越好。担任挑选被装饰的大楼的工作的JOI君,考虑到了大楼的主人可能会有“希望自己的大楼被装饰起来,而且,为了让大楼很显眼,希望这栋大楼是所有装饰起来的大楼中离宿舍最近的一栋”这种无理要求。
从机场到宿舍沿路共有N栋大楼,从机场开始的第i栋大楼称作大楼i,N栋大楼的高度彼此不同。JOI君为了满足各种各样的要求,决定事先计算出“如果装饰大楼i,并且让大楼i是所有装饰起来的大楼中离宿舍最近的一栋,那么选出的大楼最多有Ai个”这样的东西。JOI君计算出了整数列A1,A2,...,AN,然后发给了日本信息学奥林匹克竞赛委员会的K理事长。
然而,K理事长收到的信息只有一个长度为N-1的整数列B1,B2,...,B[N-1]。K理事长不知道大楼高度的情报,因此没有办法计算出Ai。
K理事长认为,JOI君一定是漏写了一个数。考虑到以A1,A2,...,AN为A数组的大楼的高度大小关系可能有很多种,K理事长想知道,删掉一个数后能得到B1,B2,...,B[N-1]的合法的A数组一共有多少种?
然而实际上,JOI君有可能并没有漏写一个数而是出现了其他的书写事故,因此无解也是有可能的。

Input

第一行一个正整数N,表示从机场到宿舍沿路的大楼数量。
接下来N-1行,第i行(1<=i<=N-1)为Bi,表示K理事长收到的第i个数的值。

Output

输出一行一个正整数,表示可能的A数组的数量

Sample Input

4
1
1
2

Sample Output

5
【HINT】
合法的A数组共有以下5种:
1,2,1,2,此时的高度序列为2413或3412
1,1,2,3,此时的高度序列为2134
1,1,2,1,此时的高度序列为3241
1,1,2,2,此时的高度序列为2143
1,1,1,2,此时的高度序列为3214

Data Constraint

对于10%的数据,N<=8
对于40%的数据,N<=300
对于100%的数据:
2<=N<=10^6
1<=Bi<=N (1<=i<=N-1)

Solution

容易知道A序列是以i为结尾的最长上升子序列的长度。

根据朴素算法:  f[ i ]= max{  f[ j ] } +1

有:max{ h[ 1~ i-1 ] } + 1 >= h[ i ]

或者前面一定有一个 A [ j ] 使得 A[ j ] +1=A[ i ] (此时满足 h[ i ]> h[ j ])

首先先删掉不合法的情况。我们只能插入一个数,所以当

1. A[ i ] - max{ A[ 1~ i-1 ] }  >2 时,不合法。

2. A[ i ]- max{ A[ 1~ i-1 ] } =2 时,必须在中间加入一个数,但是如果有两个或以上这样的 i 存在时,不合法。

很自然,接下来对于上面只有一个 i 满足 A[ i ]- max{ A[ 1~ i-1 ] } =2 时,Ans= i - k ( k 为max{ A[ 1~ i-1 ] } 中A[ k ]最大的位置 k )

除此之外,就是一定能满足的情况了。

那么在数列前面可以补上一个0,然后对于序列中每一个相同的数中A[ i ]={0,1,2,3...}最前的那一个数,都可以在其后面加入一个 A[ i ]+1 ,这样可以保证加入的 A[ i ]+1 可以由前面转移过来,因此答案的个数为n-i+1。(其中n为未加入数之前的序列长度),但是其中由重复的部分,我们发现所有  i 位置 后面的 A[ i +1 ] 前面和后面同时插入 A[ i ]+1时答案时一样的,所有要减去Sum{ A[ j ]= A[ i ] +1 } ( j > i )

例如 0 1 1 2 3

在 0 的后面可以加1

1 1 1 2 3 1

0 1 1 2 3 1

0 1 1 1 2 3 1

0 1 1 2 1 3 1

0 1 1 2 3 1 1

0 1 1 2 ​​​​​​​3 1 1

重复的有:

0 1 1 1 2 3 1   (2个)

0 1 1 2 3 1 1   (1个)

即0后面1的个数。

而最早出现的0一定在最早出现的1的位置之前,最早的1也在最早的2之前,因此相当于所有数列中的数都减了一遍,因此最后答案直接减n即可。

Code

#include <algorithm>
#include <cstdio>
#include <cstring>
#define I int
#define ll long long
#define F(i,a,b) for(I i=a;i<=b;i++)
#define Fd(i,a,b) for(I i=a;i>=b;i--)
#define N 1000010
using namespace std;
I n,a[N],mx,bz[N],ok=1,tot=0,p=0;
ll ans;
I main(){
	freopen("building.in","r",stdin);
	freopen("building.out","w",stdout);
	scanf("%d",&n);n--;
	F(i,1,n){
		scanf("%d",&a[i]);
		if(a[i]-mx>2) ok=0;
		if(a[i]-mx==2){
			tot++;p=i;
			if(tot>1) ok=0;
		}
		mx=max(mx,a[i]);
	}
	if(!ok){printf("0\n");return 0;}
	if(tot){
		F(i,0,p) if(a[i]==a[p]-2){
			ans=p-i;
			break;
		}
		printf("%lld\n",ans);
		return 0;
	}
	F(i,0,n){
		if(!bz[a[i]]) ans+=n-i+1;
		bz[a[i]]=1;
	}
	printf("%lld\n",ans-n);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/zsjzliziyang/article/details/107701290