1996: [Hnoi2010]chorus 合唱队
Posted 人间失格
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了1996: [Hnoi2010]chorus 合唱队相关的知识,希望对你有一定的参考价值。
1996: [Hnoi2010]chorus 合唱队
Time Limit: 4 Sec Memory Limit: 64 MBSubmit: 1850 Solved: 1197
[Submit][Status][Discuss]
Description
Input
Output
Sample Input
4
1701 1702 1703 1704
1701 1702 1703 1704
Sample Output
8
HINT
题解:
这个题目,首先分析一下题目的性质,对于一个排列,我们要保证可以形成最终的序列,那么就必须要保证他们的相对位置不变,看一下数据范围n^2,就可以知道这个题目应该要记一下当前dp的左右端点。
当然,发现这样并不能转移,发现对于一个元素,如果处理到当前为的答案序列已经确定,他前面的数确定,那么他的位置也是确定的,所以还要记一下他当前前面的是谁,所以设dp[i][j]0/1]表示已经形成了答案串的i~j部分,上一个点是i还是j的方案数,转移十分简单。注意初始化的时候只能初始话一边(至于为什么博主也不知道,只是知道如果初始化两边,就会是答案的两倍,然后还要拓展欧几里德求逆)。
代码:
#include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #include <cmath> #include <iostream> #define MAXN 1100 #define mod 19650827 #define ll long long using namespace std; ll dp[MAXN][MAXN][2]; int n,h[MAXN]; int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&h[i]); for(int i=1;i<=n;i++) dp[i][i][0]=1; for(int len=2;len<=n;len++) for(int i=1;i<=n;i++){ int j=i+len-1;if(j>n) break; if(h[i]<h[i+1]) dp[i][j][0]=dp[i][j][0]+dp[i+1][j][0]; if(h[i]<h[j]) dp[i][j][0]=dp[i][j][0]+dp[i+1][j][1]; if(h[j]>h[i]) dp[i][j][1]=dp[i][j][1]+dp[i][j-1][0]; if(h[j]>h[j-1]) dp[i][j][1]=dp[i][j][1]+dp[i][j-1][1]; if(dp[i][j][0]>=mod) dp[i][j][0]-=mod; if(dp[i][j][1]>=mod) dp[i][j][1]-=mod; } printf("%lld",(dp[1][n][0]+dp[1][n][1])%mod); return 0; }
以上是关于1996: [Hnoi2010]chorus 合唱队的主要内容,如果未能解决你的问题,请参考以下文章
bzoj1996: [Hnoi2010]chorus 合唱队 区间dp
BZOJ1996[Hnoi2010]chorus 合唱队 区间DP
BZOJ 1996: [Hnoi2010]chorus 合唱队
bzoj 1996: [Hnoi2010]chorus 合唱队