【luogu3205】【bzoj1996】 [HNOI2010]合唱队 [区间dp]

P3205 [HNOI2010]合唱队

bzoj1996  

对从第二个人开始的每个人,如果他比前面那个人高(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 }
原文地址:https://www.cnblogs.com/lxyyyy/p/10885818.html