BZOJ1996 HNOI2010合唱队(区间dp)
设f[i][j][0/1]表示i~j这段区间上一次选择的是最左/最右人的方案数。转移显然。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } #define N 1010 #define P 19650827 int n,a[N],f[N][N][2]; void inc(int &x,int y){x+=y;if (x>=P) x-=P;} int main() { #ifndef ONLINE_JUDGE freopen("bzoj1996.in","r",stdin); freopen("bzoj1996.out","w",stdout); const char LL[]="%I64d\n"; #else const char LL[]="%lld\n"; #endif n=read(); for (int i=1;i<=n;i++) a[i]=read(); for (int i=1;i<=n;i++) f[i][i][0]=1; for (int k=2;k<=n;k++) for (int i=1;i<=n-k+1;i++) { int j=i+k-1; if (a[i]<a[i+1]) inc(f[i][j][0],f[i+1][j][0]); if (a[i]<a[j]) inc(f[i][j][0],f[i+1][j][1]); if (a[j]>a[j-1]) inc(f[i][j][1],f[i][j-1][1]); if (a[j]>a[i]) inc(f[i][j][1],f[i][j-1][0]); } cout<<(f[1][n][0]+f[1][n][1])%P; return 0; }