• [HNOI2009]双递增序列(动态规划,序列dp)


    感觉这个题还蛮难想的.
    首先状态特别难想.设(dp[i][j])表示前i个数,2序列的长度为j的情况下,2序列的最后一个数的最小值.
    其中1序列为上一个数所在的序列,2序列为另外一个序列.
    这样设状态的巧妙之处在于,它几乎完美地用最精炼的语言描述了序列的信息,使我们可以方便地转移.我们现在知道1序列的最后一个数(seq[i]),2序列的最后一个数(dp[i][j]).1序列的长度(i-j),2序列的长度(j).
    于是转移就是:
    如果可以接在1序列上的话,即(seq[i-1]<seq[i]),那么(dp[i][j]=min(dp[i][j],dp[i-1][j]))
    如果可以接在2序列上的话,即(dp[i-1][i-j]<seq[i])(可以接在2序列上,但是由于状态是2序列的长度,所以两个序列要交换,所以是i-j),那么1序列和2序列要互换,此时2序列的最后一个元素就是之前1序列的最后一个元素(seq[i-1]),即(dp[i][k]=min(dp[i][j],seq[i-1]))

    #include<bits/stdc++.h>
    #define maxn 2005
    using namespace std;
    int seq[maxn],n;
    int dp[maxn][maxn];
    //dp[i][j]表示前i个数,2序列长度为j,2序列最后一个数的最小值.
    int main()
    {
    	int T;cin>>T;
    	while(T--)
    	{
    		scanf("%d",&n);
    		for(int i=1;i<=n;i++)scanf("%d",&seq[i]);
    		memset(dp,0x3f,sizeof(dp));dp[0][0]=-1;
    		for(int i=1;i<=n;i++)
    		{
    			for(int j=0;j<=min(n/2,i);j++)
    			{
    				if(seq[i-1]<seq[i])dp[i][j]=dp[i-1][j];
                    //大于前一个数,说明可以直接接在前一个数之后,2序列的最后元素不需要变大
    				if(dp[i-1][i-j]<seq[i])dp[i][j]=min(dp[i][j],seq[i-1]);
    				//大于2序列的最后一个数,说明可以接在2序列之后,此时1序列和2序列交换
    				//本来作为数组里的值表示的现在变成下标体现,原本下标体现的现在变成值
    				//1序列表示上一次的数所在的序列,2序列是另一个序列
    				//seq[i-1]是1序列最后一个元素
    			}
    		}
    		if(dp[n][n/2]<=1e6)printf("Yes!
    ");
    		else printf("No!
    ");
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    框架
    css样式表。作用是美化HTML网页.
    表单的制作
    表格的制作
    常用标签的制作
    标签的制作
    poj2104(K-th Number)
    Codeforces Round #359 (Div. 2) D. Kay and Snowflake
    Codeforces Round #359 (Div. 2) C. Robbers' watch
    HDU3308(LCIS) 线段树好题
  • 原文地址:https://www.cnblogs.com/terribleterrible/p/9873856.html
Copyright © 2020-2023  润新知