zoukankan      html  css  js  c++  java
  • BZOJ 1996: [Hnoi2010]chorus 合唱队(区间dp)

    题目:

      https://www.lydsy.com/JudgeOnline/problem.php?id=1996

    题解:

      这题刚拿到手的时候一脸懵逼qwq,经过思考与分析(看题解),发现是一道区间dp

      首先我们考虑最终数列的形成过程,可以看做是由一个序列向左右不断加数形成的,因此,就有一个很美妙的性质:对于最终序列的任意一段,最后加入的一定是左端点或者右端点(很显然)。因此我们就考虑到了区间dp。。

      最终序列为g,定义dp[i][j][k](k==0||k==1)表示对于最终序列的i-j区间,最后加入的是左端点(g[i])(k==0),还是右端点(g[j])(k==1)。

      那么dp方程就很显然了,对于dp[i][j][1](此数放在右边),最后加入的数(g[j])一定比倒数第二个大

        (1)倒数第二个数放在了左边,那么if(g[j]>g[i]) dp[i][j][1]+=dp[i][j-1][0];

        (2)倒数第二个数放在了右边,那么if(g[j]>g[j-1]) dp[i][j][1]+=dp[i][j-1][1];

      对于dp[i][j][0]同理。。。

      区间dp最外层枚举区间长度。。(这是一句废话qwq)

      p.s.对于初始化时dp[i][i][0/1]只能将0/1其中的一个置成1,否则会导致重复计数。

    代码:

    #include<bits/stdc++.h>
    
    using namespace std;
    
    const int p=19650827;
    const int maxn=1010;
    int dp[maxn][maxn][2],g[maxn],n;
    
    int main(){
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%d",&g[i]);
        for(int i=1;i<=n;i++)
            dp[i][i][0]=1;
        for(int k=2;k<=n;k++)
            for(int i=1,j=i+k-1;j<=n;j++,i++){
                if(g[j]>g[i]) dp[i][j][1]+=dp[i][j-1][0];
                if(g[j]>g[j-1]) dp[i][j][1]+=dp[i][j-1][1];
                if(g[i]<g[j]) dp[i][j][0]+=dp[i+1][j][1];
                if(g[i]<g[i+1]) dp[i][j][0]+=dp[i+1][j][0];
                dp[i][j][0]%=p,dp[i][j][1]%=p;
            }
        printf("%d",(dp[1][n][0]+dp[1][n][1])%p);
        return 0;    
    }
  • 相关阅读:
    常见运算符_python
    hibernate中的二级缓存
    事务的隔离级别
    java hibernate 一对多和多对多映射关系总结
    hibernate中集合映射总结
    java中静态代码块之我的理解
    select下拉表达设置选中,获取选中项,change
    jquery checkbox设置选中,全选,反选,取值
    javaWeb建立一个简单三层项目具体步骤
    java 异步实现省市联动
  • 原文地址:https://www.cnblogs.com/tang666/p/8744254.html
Copyright © 2011-2022 走看看