bzoj1996: [Hnoi2010]chorus 合唱队 区间dp

Posted rubenisveryhandsome

tags:

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

 

1996: [Hnoi2010]chorus 合唱队

Time Limit: 4 Sec  Memory Limit: 64 MB
Submit: 2088  Solved: 1371
[Submit][Status][Discuss]

Description

技术分享图片

Input

技术分享图片

Output

技术分享图片

Sample Input

4
1701 1702 1703 1704

Sample Output

8

HINT

技术分享图片 

emmmm这道题是一道区间dp (因为前天考试区间dp裸题没搞出来这两天做了不少)

看到题目可以考虑到一个显然的性质 每次插入数字进去的时候要不是在队头 要不是在队尾 

那么就可以定义一个状态 $dp[i][j][0/1]$ 表示区间 $[i,j]$ 最后一个元素插在队头 / 队尾的方案数

那么初值是什么呢  按照第一想法 $dp[i][i][0] = dp[i][i][1] = 1$ 实则不然

仔细考虑一下 这个初值是错误的 因为每次插入要不是插在队头 要不是队尾

而这样的含义是 我既插在队头又插在队尾 不符合题目条件 那么这样子转移也是错误的

每次会被多计算一遍

方程式比较好推的 用刷表 每次判断我这个新元素的位置 与上一次的元素比较 如果合法方案就加上就可以了

代码

#include <bits/stdc++.h>
using namespace std;

const int mod = 19650827;
int n,dp[1005][1005][2],ans,a[1005];

void solve( ) {
    
    for(int i = 1;i <= n;i ++) dp[i][i][0] = 1;
    for(int len = 1;len <= n;len ++) {
        for(int i = 1;i + len - 1 <= n;i ++) {
            int l = i + len - 1;
            if(i - 1 >= 1) {
                dp[i-1][l][0] = (dp[i-1][l][0] + dp[i][l][0] * (a[i-1] < a[i])) % mod;
                dp[i-1][l][0] = (dp[i-1][l][0] + dp[i][l][1] * (a[i-1] < a[l])) % mod;
            }
            if(l + 1 <= n) {
                dp[i][l+1][1] = (dp[i][l+1][1] + dp[i][l][0] * (a[i] < a[l+1])) % mod;
                dp[i][l+1][1] = (dp[i][l+1][1] + dp[i][l][1] * (a[l] < a[l+1])) % mod;
            }
        }
    }
    ans = (dp[1][n][0] + dp[1][n][1]) % mod;
    printf("%d",ans);
}

int main( ) {
    
    scanf("%d",& n);
    for(int i = 1;i <= n;i ++) scanf("%d",& a[i]);
    solve( );
}

 

以上是关于bzoj1996: [Hnoi2010]chorus 合唱队 区间dp的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ1996[Hnoi2010]chorus 合唱队 区间DP

BZOJ1996HNOI2010合唱队 [区间DP]

BZOJ1996 [Hnoi2010] 合唱队

BZOJ 1996: [Hnoi2010]chorus 合唱队

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

bzoj 1996: [Hnoi2010]chorus 合唱队