zoukankan      html  css  js  c++  java
  • [LUOGU] P3205 [HNOI2010]CHORUS 合唱队

    为了在即将到来的晚会上有更好的演出效果,作为AAA合唱队负责人的小A需要将合唱队的人根据他们的身高排出一个队形。假定合唱队一共N个人,第i个人的身高为Hi米(1000<=Hi<=2000),并已知任何两个人的身高都不同。假定最终排出的队形是A 个人站成一排,为了简化问题,小A想出了如下排队的方式:他让所有的人先按任意顺序站成一个初始队形,然后从左到右按以下原则依次将每个人插入最终棑排出的队形中:
    
    -第一个人直接插入空的当前队形中。
    
    -对从第二个人开始的每个人,如果他比前面那个人高(H较大),那么将他插入当前队形的最右边。如果他比前面那个人矮(H较小),那么将他插入当前队形的最左边。
    
    当N个人全部插入当前队形后便获得最终排出的队形。
    
    例如,有6个人站成一个初始队形,身高依次为185019001700165018001750,
    
    那么小A会按以下步骤获得最终排出的队形:
    
    1850
    
    1850 , 1900 因为 1900 > 1850
    
    1700, 1850, 1900 因为 1700 < 1900
    
    1650 . 1700, 1850, 1900 因为 1650 < 1700
    
    1650 , 1700, 1850, 1900, 1800 因为 1800 > 1650
    
    17501650, 17001850, 1900, 1800 因为 1750 < 1800
    因此,最终排出的队形是 1750165017001850, 19001800
    
    小A心中有一个理想队形,他想知道多少种初始队形可以获得理想的队形
    
    输入输出格式
    输入格式:
    输出格式:
    注意要mod19650827
    
    输入输出样例
    输入样例#1: 
    4
    1701 1702 1703 1704
    输出样例#1: 
    8
    说明
    30%的数据:n<=100
    
    100%的数据:n<=1000
    
    

    往区间dp上考虑
    最终状态一定是f[1][n] 所以就把它划分成一个个小点的区间
    加一个数只能在一个小区间的左边或右边,所以
    f[i][j]可以由f[i+1][j]和f[i][j-1] 转移过来
    但是这样无法转移,所以考虑加一维
    f[i][j][0/1] 0表示左边加了一个,1表示右边加了一个
    f[i+1][j][0/1] 缺了左边一个 所以一定是向f[i][j][0]转移的
    同理 f[i][j][1]由f[i][j-1][0/1]转移来

    具体0和1,是看新加的这一位和小区间的左右(0/1)的大小关系
    比如 f[i][[j][0] <- f[i+1][j][1]
    这就是[i+1,j]转移到了[i,j] 加的一位是val[i] 而小区间[i-1][j]是又右(1)转移来的
    所以判断val[i]和val[j] 根据题目所给左小右大(符合直觉的。)

    if(val[i]<val[j]) f[i][j][0]+=f[i+1][j][1];

    类似可推出剩下3个式子

    由于是大区间依赖小区间,由短的向长的转移,所以最外层是长度len,第二层是左端点l,r=l+len

    O(n^2)

    //Stay foolish,stay hungry,stay young,stay simple
    #include<iostream>
    using namespace std;
    
    const int MAXN=1005;
    const int MOD=19650827;
    int n;
    int a[MAXN];
    int f[MAXN][MAXN][2];
    
    int main(){
        cin>>n;
        for(int i=1;i<=n;i++) cin>>a[i];
        for(int l=1;l<=n;l++){
            f[l][l][0]=1;
        }
        for(int len=1;len<=n;len++){
            for(int l=1;l+len<=n;l++){
                int r=l+len;
                if(a[l+1]>a[l]) f[l][r][0]+=f[l+1][r][0];
                if(a[r]>a[l])   f[l][r][0]+=f[l+1][r][1];
                if(a[l]<a[r])   f[l][r][1]+=f[l][r-1][0];
                if(a[r-1]<a[r]) f[l][r][1]+=f[l][r-1][1];
                f[l][r][0]%=MOD;
                f[l][r][1]%=MOD;
            }
        }
        cout<<(f[1][n][0]+f[1][n][1])%MOD;
        return 0;
    }
    

    本文来自博客园,作者:GhostCai,转载请注明原文链接:https://www.cnblogs.com/ghostcai/p/9247462.html

  • 相关阅读:
    植物园偶遇一直喵
    植物园偶遇一直喵
    美食篇
    美食篇
    端午节路过南站
    端午节路过南站
    黄山云海
    黄山云海
    Android (1)
    树和树算法(1)
  • 原文地址:https://www.cnblogs.com/ghostcai/p/9247462.html
Copyright © 2011-2022 走看看