• P1410 子序列


    P1410 子序列

    链接:https://www.luogu.com.cn/problem/P1410

    题意

    给定一个长度为N(N为偶数)的序列,问能否将其划分为两个长度为N/2的严格递增子序列。

    题解

    先考虑暴力dp,如果设状态为\(dp[i][j][l][k][r]\)表示前i项中其中一个长度为j,以l结尾,另一个长度为k,以r结尾是否可行,那这道题就做完了。(可惜\(n <= 2000\)

    考虑显然优化,因为\(j+k=i\)并且两个当中必然有一个以\(a[i]\)结尾,所以可以优化为\(dp[i][j][k]\)表示前i项以a[i]结尾的严格递增子序列长度为\(j\)是否可行,另外一个以\(k\)结尾,就优化为了\(O(n^3)\)

    考虑贪心,在\(i,j\)相同的情况下,\(dp[i][j][k]\)由最小的\(k\)转移显然是最优的(k越小\(dp[i][j][k]\)越容易转为\(true\)),而且我们可以考虑把贪心的一维压入\(dp\)值中,于是最终状态为\(dp[i][j]\)表示前i项以a[i]结尾的严格递增子序列长度为j,另一个的结尾的最小值。

    方程

    \(dp[i][j] = min(dp[i-1][i-1]) if:a[i]>a[i-1]\)

    考虑把a[i]放入以a[i - 1]结尾的序列

    \(dp[i][i-j+1] = min(a[i - 1])if:a[i] > dp[i - 1][j - 1]\)

    考虑把a[i]放入不以a[i - 1]结尾的序列

    代码(如果不理解请仔细考虑状态的意思)

    #include <bits/stdc++.h>
    using namespace std;
    #define R register
    typedef long long ll;
    const int MAXN = 2e3 + 5;
    int a[MAXN];
    int dp[MAXN][MAXN];
    int main()
    {
    	int n;
    	while(cin >> n)
    	{
    		for(R int i = 1;i <= n; i++)
    			scanf("%d", &a[i]);	
    		memset(dp,0x3f,sizeof(dp));
    		dp[1][1] = 0;
    		for(R int i = 2;i <= n; i++)
    		{
    			for(R int j = 1;j <= i; j++)
    			{
    				if(a[i] > a[i - 1])dp[i][j] = min(dp[i][j],dp[i - 1][j - 1]);	
    				if(a[i] > dp[i - 1][j - 1])dp[i][i - j + 1] = min(dp[i][i - j + 1],a[i - 1]);
    			}	
    		}
    		if(dp[n][n / 2] != 0x3f3f3f3f)printf("Yes!\n");
    		else printf("No!\n");
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    winform 窗体移动API、窗体阴影API
    winform 对话框、打印框
    winform 容器控件
    winform listview控件
    winform 计算器
    Winform 主窗体更换 构造函数传值
    Winform 菜单和工具栏控件
    0103 luffy项目配置
    0102 三大视图配置
    1230 视图家族类
  • 原文地址:https://www.cnblogs.com/XuKeQAQ/p/14530955.html
Copyright © 2020-2023  润新知