题目描述
输入格式
输出格式
样例输入
4
1701 1702 1703 1704
样例输出
8
提示
题解
发现题目要求的是方案数,那么我们想到了区间DP。
由于题目给定的加入元素的方式,我们可以清楚的知道新元素要么加在队头要么加在队尾,所以说在某种程度上这个序列是连续的(或者说有特殊的性质),并且对于新加入的元素的位置的影响只跟上一次的加入元素有关。
根据这个特殊性质我们想到了区间DP,令
f[l][r][0or1]
表示区间l~r中现在加入的元素放在队头\队尾。
那么显然,初值即为
f[i][i][0]=1
或
f[i][i][1]=1
,并且如果放在队头的话
f[l][r][0]
应该从
f[l+1][r][0or1]
推导过来,继续思考发现从
f[l+1][r][0]
推导过来的条件是
a[l]<a[l+1]
,从
f[l][r][1]
推导过来的条件则应该是
a[l]<a[r]
,
f[l][r][1]
情况类似。
这样跑一遍区间DP最后答案显然就是
f[1][n][0]+f[1][n][1]
了。
转移方程:
f[i][j][0/1]
表示取到数列中从i到j的区间,上一个取到的是数列左边/右边的数
f[i][j][0]=f[i+1][j][0]∗(a[i]<a[i+1])+f[i+1][j][1]∗(a[i]<a[j])
f[i][j][1]=f[i][j+1][0]+(a[j]>a[i])+f[i][j+1][1]∗(a[j]>a[j−1])
代码
#include <cstdio>
#include <cstring>
#include <algorithm>
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
const int size = 1000+10;
const int mod = 19650827;
int a[size],f[size][size][2];
int n;
inline int read(int &in) {
in=0;int f=1;char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar()) if(ch=='-') f=-1;
for(;ch>='0'&&ch<='9';ch=getchar()) in=in*10+ch-'0';
return in*f;
}
int main() {
read(n);
for(int i=1;i<=n;i++) read(a[i]);
for(int i=1;i<=n;i++) f[i][i][1]=1;
for(int i=n;i>=1;i--)
for(int j=i+1;j<=n;j++) {
if (a[i]<a[i+1])f[i][j][0]+=f[i+1][j][0];
if (a[i]<a[j])f[i][j][0]+=f[i+1][j][1];
if (a[j]>a[i])f[i][j][1]+=f[i][j-1][0];
if (a[j]>a[j-1])f[i][j][1]+=f[i][j-1][1];
f[i][j][0]%=mod; f[i][j][1]%=mod;
}
printf("%d\n",(f[1][n][0]+f[1][n][1])%mod);
return 0;
}