1996: [Hnoi2010]chorus 合唱队

Posted 人间失格

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了1996: [Hnoi2010]chorus 合唱队相关的知识,希望对你有一定的参考价值。

1996: [Hnoi2010]chorus 合唱队

Time Limit: 4 Sec  Memory Limit: 64 MB
Submit: 1850  Solved: 1197
[Submit][Status][Discuss]

Description

技术分享

Input

技术分享

Output

技术分享

Sample Input

4
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 合唱队

bzoj千题计划211:bzoj1996: [Hnoi2010]chorus 合唱队

[HNOI2010]CHORUS 合唱队