P3607 [USACO17JAN] Subsequence Reversal P

这道题看到前面就是最长上升子序列问题(不严格单调递增)

但是他又说在求这个最长上升子序列之前可以将任意一个序列旋转一次就是将其中元素组成的序列进行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]);
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值