动态规划:P3205[HNOI2010]合唱队 区间DP

P3205[HNOI2010]合唱队

 

 题目大意:

    题目的意思其实就是给你一个最终的序列,问有几种方法可以排成最终的序列。(我一开始给理解成了是给你一个序列,问能派出多少种序列.......),所以显然是用区间DP:这题目给你了最终的序列,就相当于区间确定了,最终答案肯定就是DP[1][N],只是这个区间是怎么构成的需要计算,大区间肯定是由小区间延伸而来,但大区间和小区间之间的关系,与小区间最后一个排的人在左边还是在右边有关,所以就需要构建一个三维的DP,第三维仅仅有2,分别是0和1,表示最后一个人插在左边和插在右边。就得到了状态转移方程:

 

 完整AC代码:

    就是正常区间DP,需要注意的就是最后的ans是DP[1][N][0]+DP[1][N][1],还有初始条件:只有一个人的时候,初始化dp[i][i]=1,这里假设一开始都是把一个人插在空的左边,所以先只初始化dp[i][i][0]=1:

 1 #include<iostream>
 2 #include<cmath>
 3 #include<algorithm>
 4 #include<vector>
 5 using namespace std;
 6 const int mod = 19650827;
 7 const int maxn = 1e3 + 5;
 8 int a[maxn];
 9 int dp[maxn][maxn][2];
10 int main()
11 {
12     int n;
13     cin >> n;
14     for (int i = 1; i <= n; ++i)
15         cin >> a[i],dp[i][i][0]=1;//假设一开始都在左边插入
16     for (int len = 2; len <= n; ++len)
17     {
18         for (int l = 1; l + len - 1 <= n; ++l)
19         {
20             int r = l + len - 1;
21             if (a[l] < a[l + 1])
22             {
23                 dp[l][r][0] += dp[l + 1][r][0];
24                 dp[l][r][0] %= mod;
25             }
26             if (a[l] < a[r])
27             {
28                 dp[l][r][0] += dp[l+1][r][1];
29                 dp[l][r][0] %= mod;
30             }
31             if (a[r] > a[r - 1])
32             {
33                 dp[l][r][1] += dp[l][r - 1][1];
34                 dp[l][r][1] %= mod;
35             }
36             if (a[r] > a[l])
37             {
38                 dp[l][r][1] += dp[l][r - 1][0];
39                 dp[l][r][1] %= mod;
40             }
41             
42         }
43     }
44     cout << (dp[1][n][0]+dp[1][n][1])%mod;
45     return 0;
46 }

 

 

posted @ 2022-04-20 08:55  朱朱成  阅读(48)  评论(0编辑  收藏  举报