【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)
反思&题解
比赛思路: 一脸懵……but看到有可能有无解的情况,果断输出0,高兴地骗了14分 (日本人出的题果然斯国一!!!)
正解思路: 很显然a数组的每个位置是求一次最长上升子序列,由此可得
的取值范围为
之后我们考虑不合法的情况 (也就是输出0可以骗分的情况) :
1. 相邻两个数的差值超过2,很明显怎么补进去一个数都不行
2. 有2对及以上差值等于2,1个数字只能补1个位置,所以不合法
最后把他们补进去就行了,不过记得要判一下重
反思: 数学思想要多练一练,刺激一下
CODE
#include<bits/stdc++.h>
using namespace std;
long long b[1000005],n,ans,num,mx;
int main()
{
freopen("building.in","r",stdin);
freopen("building.out","w",stdout);
scanf("%lld",&n);
int i,w,tot;
for (i=1;i<n;i++)
{
scanf("%lld",&b[i]);
mx=max(mx,b[i-1]);
if (b[i]>mx+2)
{
printf("0\n");
return 0;
}
if (b[i]==mx+2)
{
num++;
if (num==2)
{
printf("0\n");
return 0;
}
tot=mx+1;
w=i-1;
}
}
if (num)
{
mx=0;
for (i=1;i<=w;i++)
{
mx=max(mx,b[i]);
if (mx+1>=tot) ans++;
}
if (tot==1) ans++;
printf("%lld\n",ans);
}
else
{
mx=0;
for (i=1;i<n;i++)
{
mx=max(mx,b[i]);
ans+=mx+1;
if (i!=n-1 && mx+1>=b[i+1]) ans--;
}
printf("%lld\n",ans);
}
return 0;
}