首页 > 代码库 > 【BZOJ1996】【HNOI2010】合唱队 [区间DP]
【BZOJ1996】【HNOI2010】合唱队 [区间DP]
合唱队
Time Limit: 4 Sec Memory Limit: 64 MB[Submit][Status][Discuss]
Description
Input
Output
Sample Input
4
1701 1702 1703 1704
1701 1702 1703 1704
Sample Output
8
HINT
Main idea
给定一个元素两两不相等的目标序列,每次按照给定方式将一个元素加入到序列当中,问得到目标序列的方案有几种。(加元素的方式:如果加的这个元素比上一个加入的元素小的话则放在队头,否则放在队尾)。
Source
发现题目要求的是方案数,并且没有什么一眼看过去的规律,不可能是找规律了,那么我们想到了区间DP。
由于题目给定的加入元素的方式,我们可以清楚的知道新元素要么加在队头要么加在队尾,所以说在某种程度上这个序列是连续的(或者说有特殊的性质),并且对于新加入的元素的位置的影响只跟上一次的加入元素有关。
根据这个特殊性质我们想到了区间DP,令f[l][r][0\1]表示区间l~r中现在加入的元素放在队头\队尾。
那么显然,初值即为f[i][i][0]=1或f[i][i][1]=1,并且如果放在队头的话f[l][r][0]应该从f[l+1][r][0\1]推导过来,继续思考发现从f[l+1][r][0]推导过来的条件是a[l]<a[l+1],从f[l][r][1]推导过来的条件则应该是a[l]<a[r],f[l][r][1]情况类似。
这样跑一遍区间DP最后答案显然就是f[1][n][0]+f[1][n][1]了。
Code
1 #include<iostream> 2 #include<algorithm> 3 #include<cstdio> 4 #include<cstring> 5 #include<cstdlib> 6 #include<cmath> 7 #include<queue> 8 using namespace std; 9 10 const int ONE=1005;11 const int MOD=19650827;12 13 int n;14 int a[ONE];15 int f[ONE][ONE][2];16 17 int get()18 {19 int res,Q=1; char c;20 while( (c=getchar())<48 || c>57)21 if(c==‘-‘)Q=-1;22 if(Q) res=c-48; 23 while((c=getchar())>=48 && c<=57) 24 res=res*10+c-48; 25 return res*Q; 26 }27 28 int main()29 {30 n=get();31 for(int i=1;i<=n;i++)32 {33 a[i]=get();34 }35 36 for(int i=1;i<=n;i++) f[i][i][1]=1;37 38 for(int l=n;l>=1;l--)39 for(int r=l+1;r<=n;r++)40 {41 f[l][r][0]=( f[l][r][0] + f[l+1][r][0] * (a[l]<a[l+1]) ) % MOD;42 f[l][r][0]=( f[l][r][0] + f[l+1][r][1] * (a[l]<a[r]) ) % MOD; 43 f[l][r][1]=( f[l][r][1] + f[l][r-1][0] * (a[r]>a[l]) ) % MOD;44 f[l][r][1]=( f[l][r][1] + f[l][r-1][1] * (a[r]>a[r-1]) ) % MOD;45 }46 47 printf("%d",(f[1][n][0]+f[1][n][1]) % MOD);48 }
【BZOJ1996】【HNOI2010】合唱队 [区间DP]
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。