zoukankan      html  css  js  c++  java
  • 「区间DP」「洛谷P3205」「 [HNOI2010]」合唱队

    洛谷P3205 [HNOI2010]合唱队

    题目:

    题目描述

    为了在即将到来的晚会上有更好的演出效果,作为 A 合唱队负责人的小 A 需要将合唱队的人根据他们的身高排出一个队形。假定合唱队一共 n 个人,第 i 个人的身高为 hi​ 米(1000≤hi≤2000),并已知任何两个人的身高都不同。假定最终排出的队形是 A 个人站成一排,为了简化问题,小 A 想出了如下排队的方式:他让所有的人先按任意顺序站成一个初始队形,然后从左到右按以下原则依次将每个人插入最终棑排出的队形中:

    第一个人直接插入空的当前队形中。
    
    对从第二个人开始的每个人,如果他比前面那个人高(h 较大),那么将他插入当前队形的最右边。如果他比前面那个人矮(h 较小),那么将他插入当前队形的最左边。
    

    当 n 个人全部插入当前队形后便获得最终排出的队形。

    例如,有 6 个人站成一个初始队形,身高依次为 1850,1900,1700,1650,1800,1750
    那么小 A 会按以下步骤获得最终排出的队形:

    1850 
    
    1850,1900 ,因为 1900>1850。
    
    1700,1850,1900,因为 1700<1900
    
    1650,1700,1850,1900 ,因为 1650<1700
    
    1650,1700,1850,1900,1800,因为 1800>1650
    
    1750,1650,1700,1850,1900,1800,因为 1750<1800
    

    因此,最终排出的队形是 1750,1650,1700,1850,1900,1800

    小 A 心中有一个理想队形,他想知道多少种初始队形可以获得理想的队形。

    请求出答案对 196508271 取模的值。

    输入格式

    第一行一个整数 n。
    第二行 n 个整数,表示小 A 心中的理想队形。

    输出格式

    输出一行一个整数,表示答案  % 19650827 的值。

    输入输出样例

    输入 #1

    4
    1701 1702 1703 1704

    输出 #1

    8

    思路:

    第一次遇到多状态的区间DP题,思考时间有点长

    由于总共有两种插入方式:大于前一数就放在右边,小于前一数就放在左边,由此可衍生出两种状态:新插入的数在最左边和新插入的数在最右边

    因为求得是到达最后序列的方案,就可以这样想:有多少种可能是可以到达最后序列的,可能说的不太清楚,往下看

    枚举一段区间i~j,新插入的数要么在最左端要么在最右端,所以f[0][i][j](0代表在左端插入,1相反,而f[0][i][j]则代表新插入的数在左端的所有可能序列)之前的数要么是原始序列最左端的数a[i+1]要么是最右端的数a[j],所以f[0][i][j]可以从这两个状态转移过来,前提是符合条件新插在左端a[i]要小于之前的数,f[1][i][j]同理

    接着是初状态(貌似所有区间DP初状态都得想一会),i==j肯定只有一种可能,所以把f[0][i][i]都置为1。为什么不把f[1][i][i]也置为1呢,因为i==j代表只有一个人时的方案,只有一个人时只有一种可能,总方案数f[0][i][i]+f[1][i][i]=1

    参考于洛谷第一篇博客

    代码:

    /*#!/bin/sh
    dir=$GEDIT_CURRENT_DOCUMENT_DIR
    name=$GEDIT_CURRENT_DOCUMENT_NAME
    pre=${name%.*}
    g++ -O2 $dir/$name -o $pre -g -Wall -std=c++11
    if test $? -eq 0; then
        gnome-terminal -x bash -c "time $dir/$pre;echo;read;"
    fi*/
    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    using namespace std;
    const int maxn=2e3+5,INF=0x3f3f3f3f;
    int n,f[2][maxn][maxn],a[maxn];//0左 1右
    inline int read(){
    	int s=0,w=1;
    	char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9')s=s*10+ch-'0',ch=getchar();
    	return s*w;
    }
    int main(){
    	n=read();
    	for(int i=1;i<=n;i++)a[i]=read();
    	for(int i=1;i<=n;i++)f[1][i][i]=1;
    	for(int d=2;d<=n;d++){
    		for(int i=1,j;(j=i+d-1)<=n;i++){
    			if(a[i]<a[i+1])f[0][i][j]+=f[0][i+1][j];
    			if(a[i]<a[j])f[0][i][j]+=f[1][i+1][j];//左端插入的情况,共两种可能
    			if(a[j]>a[j-1])f[1][i][j]+=f[1][i][j-1];
    			if(a[j]>a[i])f[1][i][j]+=f[0][i][j-1];//右端插入的情况,共两种可能
    			f[1][i][j]%=19650827;
    			f[0][i][j]%=19650827;
    		}
    	}
    	cout<<(f[1][1][n]+f[0][1][n])%19650827;
    
    
    }
    

    over~

  • 相关阅读:
    jQuery对DOM节点进行操作(插入节点之在元素内部插入)
    jQuery对DOM节点进行操作(创建节点)
    jQuery对元素值操作
    jQuery对元素内容操作-->对HTML内容的操作
    jQuery对元素内容操作-->对文本内容的操作
    jQuery对元素内容操作
    jQuery选择器-->注意事项
    jQuery选择器-->表单选择器
    cp 快捷命令:复制文件到多个目录
    Python-字符串
  • 原文地址:https://www.cnblogs.com/614685877--aakennes/p/13183226.html
Copyright © 2011-2022 走看看