• P4728 [HNOI2009]双递增序列


    题意

    这个DP状态有点神。

    首先考虑一个最暴力的状态:(f_{i,j,k,u})表示第一个选了(i)个,第二个选了(j)个,第一个结尾为(k),第二个结尾为(u)是否可行。

    现在考虑消减状态:

    1.首先知道了处理到第几个,那么只要知道一个长度就能推出另一个。 因此状态可以改为(f_{i,j,k,u})表示处理到了第(i)个,第一个序列选了(j)个,第一个序列结尾为(k),第二个序列结尾为(u)是否可行。(这并没有减少维数,只是转化下,方便处理。)

    2.既然所有的数都要选,假设当前处理到了第(i)个,那么第(i-1)个必定在结尾,因此我们可以消去一维:
    (f_{i,j,k})表示处理到第(i)个,结尾是(a_i)的那个序列长度为(j),另一个结尾为(k)是否可行。

    3.贪心地想,一个序列结尾越小越容易接数,因此可以将一维放到DP的值中:
    (f_{i,j})表示处理到第(i)个,结尾是(a_{i-1})的那个序列长度为(j),另一个结尾最小是多少。

    现在我们已经将DP减到二维,于是就可以转移了:

    (a_i>a_{i-1}):此时(a_i)可以拼接在(a_{i-1})后面:
    (f_{i,j}=min(f_{i,j}f_{i-1,j-1}))

    (a_i>f_{i-1,i-j}):此时我们可以将(a_i)接到另一个序列后面,于是我们交换两个序列,因为另一个序列后面接了(a_i),我们要符合定义,于是可得:
    (f_{i,j}=min(f_{i,j},a_{i-1}))

    最后判断(f_{n,n/2})是否为(inf)

    数据范围不知道,到某dark上看了看,(nleqslant2000)

    code:

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=2010;
    int T,n;
    int a[maxn];
    int f[maxn][maxn];
    int main()
    {
    	scanf("%d",&T);
    	while(T--)
    	{
    		scanf("%d",&n);
    		for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    		memset(f,0x3f,sizeof(f));
    		f[0][0]=-1;
    		for(int i=1;i<=n;i++)
    			for(int j=1;j<=min(n/2,i);j++)
    			{
    				if(a[i]>a[i-1])f[i][j]=min(f[i][j],f[i-1][j-1]);
    				if(a[i]>f[i-1][i-j])f[i][j]=min(f[i][j],a[i-1]);
    			}
    		puts(f[n][n/2]<0x3f3f3f3f?"Yes!":"No!");
    	}
    	return 0;
    }
    
  • 相关阅读:
    利用百度地图API实现百度地图坐标拾取
    newtonsoft.json的JObject里的JSON数据 动态
    监听微信返回按钮
    C# 如何理解如下泛型约束 class A<T>:where T:class{}
    微博数据库设计 _转
    新浪微博,腾讯微博mysql数据库主表猜想 __转
    Ferris教程学习笔记:js示例3.9 倒计时时钟
    Ferris教程学习笔记:js示例3.8 简易网页时钟
    Ferris教程学习笔记:js示例3.6 判断数字是否为两位数
    Ferris教程学习笔记:js示例3.5 页面加载后累加,自加1
  • 原文地址:https://www.cnblogs.com/nofind/p/12068936.html
Copyright © 2020-2023  润新知