[HNOI2010] 合唱队 chorus
标签:区间DP。
题解:
首先分析题目,根据题目中的列队方式以及数据范围,我们容易想到O(n2)的算法,也就是区间DP。发现直接dp[L][R],不能转移,于是添加一个dp[L][R][0/1],0表示这个区间最后从左边插入,1则表示右边。
然后分析从左边插入,上一个数要么是从左的要么是从右的,因为这个数在左,所以都要比他们大才符合条件。故(H[L]<H[L+1]||H[L]<H[R]),符合条件才能转移:dp[L][R][0]=dp[L+1][R][0]*(H[L]<H[L+1])+dp[L+1][R][1]*(H[L]<H[R]);
从右边插入类似:(H[R]>H[L]||H[R]>H[R-1]),dp[L][R][1]=dp[L][R-1][0]*(H[R]>H[L])+dp[L][R-1][1]*(H[R]>H[R-1]);
然后答案自然就是dp[1][n][0]+dp[1][n][1]了。
1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #define LL long long 5 using namespace std; 6 const int MAXN=1100,mod=19650827,INF=0x3f3f3f3f; 7 int n; 8 int H[MAXN],dp[MAXN][MAXN][2]; 9 int gi(){ int res; scanf("%d",&res); return res;} 10 int main() 11 { 12 freopen("chorus.in","r",stdin); 13 freopen("chorus.out","w",stdout); 14 n=gi(); 15 for(int i=1;i<=n;i++) H[i]=gi(); 16 for(int i=1;i<n;i++) 17 { 18 if(H[i]<H[i+1]) 19 { 20 dp[i][i+1][0]=1; 21 dp[i][i+1][1]=1; 22 } 23 } 24 for(int i=2;i<n;i++) 25 { 26 for(int j=1;j+i<=n;j++) 27 { 28 int L=j,R=j+i; 29 dp[L][R][0]=(dp[L+1][R][0]*(H[L]<H[L+1])+dp[L+1][R][1]*(H[L]<H[R]))%mod; 30 dp[L][R][1]=(dp[L][R-1][0]*(H[R]>H[L])+dp[L][R-1][1]*(H[R]>H[R-1]))%mod; 31 } 32 } 33 printf("%d\n",(dp[1][n][0]+dp[1][n][1])%mod); 34 return 0; 35 }