网址: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.
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 the number of elements that can possibly form a longest increasing subsequence after reversing the contents of at most one subsequence.
9
1
2
3
9
5
6
8
7
4
9
这道题目的解法非常精彩。
我简要分析。
考虑实际操作的时候,翻转相当于元素交换,换句话说,就是挑偶数个数,从里向外(反过去一样)交换元素。
我们将一次性的操作转化为有约束条件的连续操作了。
考虑状态定义。不妨设\(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\)两个数不交换,交换的话特判一下即可。约束条件变窄可以。
#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\n", dp[1][n][1][50]);
return 0;
}
这道题的整个做法实在精彩!题目的转化值得回味。
[USACO17JAN]Subsequence Reversal
原文:https://www.cnblogs.com/zach20040914/p/13548681.html