这道题看到前面就是最长上升子序列问题(不严格单调递增)
但是他又说在求这个最长上升子序列之前可以将任意一个序列旋转一次就是将其中元素组成的序列进行reserve操作
首先,我们设一个数组 dpl,r,L,R,表示从 l
到 r
的区间,值域为 L到R
的最大价值。
转移方程:我们先看看它不转换序列,最大价值,则为
dp[l][r][L][R]=max(dp[l][r][L+1][R],dp[l][r][L][R-1]);//把小值域的价值转换到大值域
dp[l][r][L][R]=max(dp[l][r][L][R],dp[l+1][r][L][R]+(a[l]==L));//向左扩展
dp[l][r][L][R]=max(dp[l][r][L][R],dp[l][r-1][L][R]+(a[r]==R));//向右扩展
接下来考虑序列转移后,转移方程怎么弄,既然要转换,也要是最长不下降子序列,则要判断,转换后,是否是最长不下降子序列,则为
dp[l][r][L][R]=max(dp[l][r][L][R],dp[l+1][r-1][L][R]+(a[l]==R)+(a[r]==L));//序列翻转后,最大价值
#include<bits/stdc++.h>
using namespace std;
const int N = 52;
int a[N], f[N][N][N][N];
void chmax(int &x, int y) {
if (x < y)x = y;
}
int main() {
int n, i, l, r, down, up;
scanf("%d", &n);
for (i = 1; i <= n; ++i) {
scanf("%d", a + i);
for (down = 1; down <= a[i]; ++down)
for (up = a[i]; up <= 50; ++up)
f[i][i][down][up] = 1;
}
for (int l1 = 2; l1 <= n; ++l1)
for (l = 1, r = l1; r <= n; ++l, ++r)
for (int l2 = 1; l2 <= 50; ++l2)
for (down = 1, up = l2; up <= 50; ++down, ++up) {
int ans = max(f[l][r][down + 1][up], f[l][r][down][up - 1]);
chmax(ans, f[l + 1][r][down][up] + (down == a[l]));
chmax(ans, f[l][r - 1][down][up] + (up == a[r]));
chmax(ans, f[l + 1][r - 1][down][up] + (down == a[r]) + (up == a[l]));
f[l][r][down][up] = ans;
}
printf("%d\n", f[1][n][1][50]);
}