国际信息学奥林匹克竞赛将要在日本召开了。为了欢迎全世界的选手们,委员会决定将从机场到宿舍沿路的大楼装饰起来。根据某著名设计师的设计,做装饰的大楼从机场到宿舍的方向必须高度严格递增。也就是说,如果做装饰的大楼从机场开始高度顺次为h1,h2,h3,…,那么必须满足h1
第一行一个正整数N,表示从机场到宿舍沿路的大楼数量。
接下来N-1行,第i行(1<=i<=N-1)为Bi,表示K理事长收到的第i个数的值。
输出一行一个正整数,表示可能的A数组的数量
4
1
1
2
5
合法的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
对于10%的数据,N<=8
对于40%的数据,N<=300
对于100%的数据:
2<=N<=10^6
1<=Bi<=N (1<=i<=N-1)
比赛思路: 一脸懵……but看到有可能有无解的情况,果断输出0,高兴地骗了14分 (日本人出的题果然斯国一!!!)
正解思路: 很显然a数组的每个位置是求一次最长上升子序列,由此可得 b [ i ] b[i] b[i]的取值范围为 [ 1 , n − 1 ] [1,n-1] [1,n−1]
之后我们考虑不合法的情况 (也就是输出0可以骗分的情况) :
1. 相邻两个数的差值超过2,很明显怎么补进去一个数都不行
2. 有2对及以上差值等于2,1个数字只能补1个位置,所以不合法
最后把他们补进去就行了,不过记得要判一下重
反思: 数学思想要多练一练,刺激一下
#include
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;
}