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
";
#else
    const char LL[]="%lld
";
#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;
}
原文地址:https://www.cnblogs.com/Gloid/p/9769964.html