动态规划: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 }