Description

国际信息学奥林匹克竞赛将要在日本召开了。为了欢迎全世界的选手们,委员会决定将从机场到宿舍沿路的大楼装饰起来。根据某著名设计师的设计,做装饰的大楼从机场到宿舍的方向必须高度严格递增。也就是说,如果做装饰的大楼从机场开始高度顺次为h1,h2,h3,...,那么必须满足h1<h2<h3<...。

从机场到宿舍沿路共有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君有可能并没有漏写一个数而是出现了其他的书写事故,因此无解也是有可能的。

Solution

大致讲下题意

有一个N个数的数列h,每个数都在在[1,N]的区间内且互不相同,定义A[i]表示从h[1]~h[i]的最长不降子序列长度

现在给出将A数组删掉一个元素剩下的B数组,求原先的A数组有多少中合法可能

我们先不考虑无解的情况

设S[i]表示Max(a[j]),且有(1≤j≤i−1)
由最长不下降子序列的定义,我们可以发现1≤A[i]≤S[i]+1

然而满足上面的条件一定有h数列与之对应吗?
确实是的,证明请参考

​http://(留坑待我下次再填)​

所以扫到第i位和第i+1位的时候答案加上S[i]+1
于是答案就有了——吗?

NoNoNo

比如说B数组是这样的

1 1 2

我们在2前面任何一个位置插入一个1
得到的结果都是

1 1 1 2

如何判重?

下面介绍一种简单的方法

假设我们当前扫到原来B数组两个1中间

当前的S[i]是1

我们发现,如果枚举的这一位与下一位B[i+1]是相同的,那么就会出现重复(即不能取1)

显然,只有当现在的S[i]+1≥B[i+1]时才能取到B[i+1]
此时将答案-1即可

然而B有可能出现断层,即无解

当存在B[i]+2<B[i+1]时,即使用删除的那一个补上也没有用了,所以无解

当存在两处B[i]+2=B[i+1]时,删除的一个只能补上一处,所以也无解。

如果只有一处B[i]+2=B[i+1],删除的一个必须在1~i之间,且删除的值必须是B[i]+1

那么1~i之间有多少个j使得S[j]+1≥B[i]+1即是这种情况的答案

Code

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fod(i,a,b) for(i=a;i>=b;i--)
using namespace std;
int a[1000001],n;
long long ans;
int main()
{
cin>>n;
int i,j=0,k=0,wz,lim;
fo(i,1,n-1)
{
if (i!=1) j=max(j,a[i-1]);
scanf("%d",&a[i]);
if (a[i]>j+2)
{
cout<<0;
return 0;
}
if (a[i]==j+2)
{
k++;
lim=j+1;
wz=i-1;
}
if (k>=2)
{
cout<<0;
return 0;
}
}
if (k==1)
{
k=0;
if (lim==1) ans++;
fo(i,1,wz)
{
k=max(k,a[i]);
if (k+1>=lim) ans++;
}
cout<<ans;
return 0;
}
fo(i,1,n-1)
{
k=max(k,a[i]);
ans+=k+1;
if (i!=n-1)
{
if (k+1>=a[i+1]) ans--;
}
}
cout<<ans;
}