zoukankan      html  css  js  c++  java
  • [USACO17JAN]Subsequence Reversal

    题目:Subsequence Reversal

    网址:https://www.luogu.com.cn/problem/P3607

    题目描述

    Farmer John is arranging his (N) cows in a line to take a photo ((1 leq N leq 50)). The height of the (i)th cow in sequence is (a(i)), and Farmer John thinks it would make for an aesthetically pleasing photo if the cow lineup has a large increasing subsequence of cows by height.

    To recall, a subsequence is a subset (a(i_1), a(i_2), ldots, a(i_k)) of elements from the cow sequence, found at some series of indices (i_1 < i_2 < ldots < i_k). We say the subsequence is increasing if (a(i_1) leq a(i_2) leq ldots leq a(i_k)).

    FJ would like there to be a long increasing subsequence within his ordering of the cows. In order to ensure this, he allows himself initially to choose any subsequence and reverse its elements.

    For example, if we had the list
    
    1 6 2 3 4 3 5 3 4
    We can reverse the chosen elements
    
    1 6 2 3 4 3 5 3 4
      ^         ^ ^ ^
    to get
    
    1 4 2 3 4 3 3 5 6
      ^         ^ ^ ^
    

    Observe how the subsequence being reversed ends up using the same indices as it initially occupied, leaving the other elements unchanged.

    Please find the maximum possible length of an increasing subsequence, given that you can choose to reverse an arbitrary subsequence once.

    Input

    The first line of input contains (N). The remaining (N) lines contain (a(1) ldots a(N)), each an integer in the range (1 ldots 50).

    Output

    Output the number of elements that can possibly form a longest increasing subsequence after reversing the contents of at most one subsequence.

    输入输出样例

    输入 #1

    9
    1
    2
    3
    9
    5
    6
    8
    7
    4
    

    输出 #1

    9
    

    这道题目的解法非常精彩。

    我简要分析。

    1. 最长上升子序列;
      方程显然成立:(dp[i] = max(dp[j] + 1))
    2. 求解任意区间内的最长上升子序列;
      (dp[i,j])为区间([i,j])中最长上升子序列长度;
      但状态刻画不清晰,应改为选(a_i)为第(1)个数的最长上升子序列;
      对此状态,有:(dp[i,j]=max(dp[k,j]+1))
    3. 对于一个序列,允许挑选一个子序列进行翻转,求最长上升子序列。
      我们先不考虑怎么做,反之,解决翻转的问题。

    考虑实际操作的时候,翻转相当于元素交换,换句话说,就是挑偶数个数,从里向外(反过去一样)交换元素。
    我们将一次性的操作转化为有约束条件的连续操作了。

    考虑状态定义。不妨设 (dp[i,j,d,u]) 代表 ([i,j]) 中最小值不小于 (d),最大值不大于 (u) 的LIS。
    先写转移。
    (dp[i,j,d,u]=max(max(dp[i+1,j,d,u]+(a[i]==d),dp[i,j-1,d,u]+(a[j]==u),dp[i+1,j-1,d,u]+(a[i]==u)+(a[j]==d)),max(dp[i,j,d+1,u],dp[i,j,d,u-1])))
    首先,([i,j])(a_i)(a_j) 两个数不交换,交换的话特判一下即可。约束条件变窄可以。

    C ++ AC代码

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    using namespace std;
    const int SIZE = 50 + 5;
    int n, a[SIZE] = {}, dp[SIZE][SIZE][SIZE][SIZE] = {};
    int main()
    {
    	scanf("%d", &n);
    
    	for(int i = 1; i <= n; ++ i) scanf("%d", &a[i]);
    	for(int i = 1; i <= n; ++ i)
    	{
    		for(int d = 1; d <= a[i]; ++ d)
    		{
    			for(int u = a[i]; u <= 50; ++ u)
    			{
    				dp[i][i][d][u] = 1;
    			}
    		}
    	}
    	for(int len1 = 2; len1 <= n; ++ len1)
    	{
    		for(int i = 1, j = len1; j <= 50; ++ i, ++ j)
    		{
    			for(int len2 = 2; len2 <= 50; ++ len2)
    			{
    				for(int d = 1, u = len2; u <= 50; ++ d, ++ u)
    				{
    					int &ans = dp[i][j][d][u];
    					ans = max(dp[i + 1][j][d][u] + (a[i] == d), dp[i][j - 1][d][u] + (a[j] == u));
    					ans = max(ans, dp[i + 1][j - 1][d][u] + (a[j] == d) + (a[i] == u));
    					ans = max(ans, dp[i][j][d + 1][u]);
    					ans = max(ans, dp[i][j][d][u - 1]);
    				}
    			}
    		}
    	}
    	printf("%d
    ", dp[1][n][1][50]);
    	return 0;
    }
    

    总结回顾

    这道题的整个做法实在精彩!题目的转化值得回味。

    参考文献

  • 相关阅读:
    通过Jenkins调用自动部署war包及jar包到服务器上的Shell脚本
    CentOS7.3+MySQL5.7+Apache2.4+PHP7.1+phpMyAdmin4.7+JDK1.8+SVN1.6+Jenkins2.1环境搭建
    telegraf1.8+influxdb1.6+grafana5.2 环境搭建 结合JMeter3.2
    HttpRunner环境搭建
    Jenkins中启动从节点时,出现问题如何解决,问题:No Known Hosts...
    python读xml文件
    使用poi或jxl,通过java读写xls、xlsx文档
    编写生成32位大写和小写字符的md5的函数
    将一个字符与对应Ascii码互转
    生成随机删除的航班信息
  • 原文地址:https://www.cnblogs.com/zach20040914/p/13548681.html
Copyright © 2011-2022 走看看