洛谷 P3205 [HNOI2010] 合唱队

思路

先设 d p i j dpij dpij 为区间 i , j i, j i,j 的队形方案数。

考虑如何转移:对于区间 i , j i, j i,j 来说,最后一个入队的要么是 i i i,要么是 j j j。

所以分类讨论:

  1. 当 j j j 为最后一个入队的时, i i i 与 j − 1 j - 1 j−1 都可能是倒数第二个入队的。要满足的条件分别是 h i < h j hi < hj hi<hj 和 h j − 1 < h i hj - 1 < hi hj−1<hi
  2. 当 i i i 为最后一个入队的时, j j j 与 i + 1 i + 1 i+1 都可能是倒数第二个入队的。要满足的条件分别是 h i < h j hi < hj hi<hj 和 h i < h i + 1 hi < hi + 1 hi<hi+1

发现上一个状态有两种,即:在上一个状态中,最后一个进来的数(也就是当前状态的倒数第二个进来的数)是在【队尾/队头】。

因此我们要丰富一下状态定义:设 d p i j 0 dpij0 dpij0 表示最后一个进来的数在【队头】的方案数, d p i j 1 dpij1 dpij1 表示最后一个进来的数在【队尾】的方案数。最后答案就是 d p 1 n 0 + d p 1 n 1 dp1n0 + dp1n1 dp1n0+dp1n1

代码

cpp 复制代码
#include <bits/stdc++.h>

using namespace std;

const int maxn = 1e3 + 7;
const int mod  = 19650827;

int n, a[maxn];
int dp[maxn][maxn][2];
int main() {
	scanf("%d", &n);
	for (int i = 1; i <= n; ++i)
	    scanf("%d", a + i), 
		dp[i][i][0] = 1;

	for (int len = 2; len <= n; ++len) {
		for (int i = 1; i + len - 1 <= n; ++i) {
			int j = i + len - 1;
			
			if (a[i] < a[j]) dp[i][j][1] = (dp[i][j][1] + dp[i][j - 1][0]) % mod;
			if (a[j - 1] < a[j]) dp[i][j][1] = (dp[i][j][1] + dp[i][j - 1][1]) % mod;
		    
		    if (a[i] < a[j]) dp[i][j][0] = (dp[i][j][0] + dp[i + 1][j][1]) % mod;
			if (a[i] < a[i + 1]) dp[i][j][0] = (dp[i][j][0] + dp[i + 1][j][0]) % mod;
		}
	}
	printf("%d\n", (dp[1][n][0] + dp[1][n][1]) % mod);
	return 0;
} 
相关推荐
彧azz1 天前
算法设计与分析:贪心与动态规划
数据结构·学习·算法·贪心算法·动态规划
Logic1013 天前
C语言/数据结构动态规划题解:Kadane算法求最大子数组和——O(n)时间O(1)空间
c语言·数据结构·动态规划·贪心·时间复杂度·算法题·最大子数组和
梦帮科技3 天前
AI 音乐产品的发布工程:验证门、数据发布、回滚与生产运维纪律
数据结构·数据库·架构·node.js·音视频·动态规划·推荐算法
语戚3 天前
力扣 1621. 大小为K的不重叠线段的数目:动态规划(Java 实现)
java·算法·leetcode·动态规划·力扣·dp
青山木3 天前
Hot 100 --- 最长有效括号
java·数据结构·算法·leetcode·动态规划
这料鬼有毒3 天前
二刷hot100-1143.最长公共子序列
算法·leetcode·动态规划
Tisfy4 天前
LeetCode 1477.找两个和为目标值且不重叠的子数组:滑动窗口 + 记录前值(动态规划)
动态规划·题解·dp·滑动窗口
ynchyong5 天前
动态规划解题思路:入门篇
动态规划
Tisfy5 天前
LeetCode 2472.不重叠回文子字符串的最大数目:动态规划(贪心)
动态规划·字符串·题解·贪心·dp·回文字符串
青山木6 天前
Hot 100 --- 最长递增子序列
java·数据结构·算法·leetcode·动态规划