【luogu3205】【bzoj1996】 [HNOI2010]合唱队 [区间dp]
对从第二个人开始的每个人,如果他比前面那个人高(H较大),那么将他插入当前队形的最右边。如果他比前面那个人矮(H较小),那么将他插入当前队形的最左边。
给定一串序列,问有多少种初始序列经过如题操作可以得到此序列。
很容易想到每一个状态是由最后一个决策决定的
所以就是区间dp的一个经典状态 f[l,r]由最后一步决定 枚举长度
如果a[l]<[r]就由两种状态转移过来 然后是l和l+1比较 r和r-1比较 来判断决策
具体靠代码感性理解
1 #include<iostream> 2 #include<cstdio> 3 #include<queue> 4 #include<cstring> 5 #include<cmath> 6 #include<stack> 7 #include<algorithm> 8 using namespace std; 9 #define ll long long 10 #define rg register 11 const int N=1000+5,inf=0x3f3f3f3f,P=19650827; 12 int n,a[N],f[N][N][2]; 13 template <class t>void rd(t &x) 14 { 15 x=0;int w=0;char ch=0; 16 while(!isdigit(ch)) w|=ch=='-',ch=getchar(); 17 while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar(); 18 x=w?-x:x; 19 } 20 21 int main() 22 { 23 freopen("in.txt","r",stdin); 24 //freopen("nocows.out","w",stdout); 25 rd(n); 26 for(rg int i=1;i<=n;++i) rd(a[i]),f[i][i][0]=1; 27 for(rg int i=2;i<=n;++i) 28 for(rg int l=1;l<n&&l+i-1<=n;++l) 29 { 30 int r=i+l-1; 31 if(a[l]<a[l+1]) f[l][r][0]=(f[l][r][0]+f[l+1][r][0])%P; 32 if(a[r]>a[r-1]) f[l][r][1]+=f[l][r-1][1]; 33 if(a[l]<a[r]) f[l][r][1]+=f[l][r-1][0]; 34 if(a[l]<a[r]) f[l][r][0]+=f[l+1][r][1]; 35 f[l][r][0]%=P,f[l][r][1]%=P; 36 } 37 printf("%d",(f[1][n][0]+f[1][n][1])%P); 38 return 0; 39 }