合唱队——区间dp

P3205 [HNOI2010]合唱队 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

 一道刚开始把我唬住的题。看完题解发现,emmmmm也没那么难。

每个人进入队伍里,只有2种可能,1种是从左边加入,另外1种是从右边进入,所以我们的状态表示是有3个数

f[i][j][0]表示的是第i人从左边进来的方案数量

f[i][j][1]表示的是第j人从右边进来的方案数量

 

状态计算:

从左边进来肯定前1个人比他高,前1个人有2种情况,要么在i+1号位置,要么在j号位置。

同理

从右边进来肯定前1个人比他矮,前1个人有2种情况,要么在j-1号位置,要么在i号位置。

 

最终求的是f[1][n][1]+f[1][n][0]的值

初始化f[1][n][0]=1,不要把右边也初始化为1.这样如果只有一个人的话,最终方案就有两个值了,那就错了。所以咱们默认第一个人从左边进来。

 

但是看完题解,我不明白为什么f[1][n][1]+f[1][n][0]就可以表示题中他希望的完美排列。后来我仔细思考了一下,因为完美排列就是这n个数经过不同的排列方式最终得到的,使得最终排列是1到n从左到右排列出来的。

 

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int N=1e3+100,mod=19650827;
 4 int a[N],f[N][N][2];
 5 
 6 int main()
 7 {
 8     int n;scanf("%d",&n);
 9     for(int i=1;i<=n;i++)scanf("%d",&a[i]);
10     for(int i=1;i<=n;i++)f[i][i][0]=1;
11     for(int len=1;len<=n;len++)
12     {
13         for(int i=1;i+len-1<=n;i++)
14         {
15             int j=i+len-1;
16             if(a[i]<a[i+1])f[i][j][0]+=f[i+1][j][0];
17             if(a[i]<a[j])f[i][j][0]+=f[i+1][j][1];
18             if(a[j]>a[i])f[i][j][1]+=f[i][j-1][0];
19             if(a[j]>a[j-1])f[i][j][1]+=f[i][j-1][1];
20             f[i][j][0]%=mod;
21             f[i][j][1]%=mod;
22         }
23     }
24     
25     int ans=(f[1][n][0]+f[1][n][1])%mod;
26     printf("%d\n",ans);
27     
28     
29     
30     return 0;
31 }
View Code

 

posted @ 2022-04-04 20:33  wellerency  阅读(20)  评论(0编辑  收藏  举报