洛谷 P3607 [USACO17JAN] Subsequence Reversal P

题目来源于:洛谷

题目本质:动态规划dp,枚举

题目思路:设一个数组dp[l],[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>
#define LL long long
using namespace std;
int read() {
	int s = 0, f = 1;
	char a = getchar();
	while(a < '0' || a > '9') {
		if(a == '-') f = -1;
		a = getchar();
	}
	while(a <= '9' && a >= '0') s = s * 10 + a - '0', a = getchar();
	return s * f;
}
LL dp[55][55][55][55],n,m,a[55],p;
int main() {
	n=read();
	for(int i=1; i<=n; i++) {
		a[i]=read();
	}
	for(int i=1;i<=n;i++) {
		for(int j=1;j<=a[i];j++) {
			for(int k=a[i];k<=50;k++) {
				dp[i][i][j][k]=1;
			}
		}
	}
	for(int len=2;len<=n;len++) {
		for(int l=1;l<=n;l++) {
			int r=l+len-1; if(r>n) break;
			for(int i=1;i<=50;i++) {
				for(int j=i;j<=50;j++) {
					dp[l][r][i][j]=max(dp[l][r][i][j],max(dp[l+1][r][i][j]+(a[l]==i),dp[l][r-1][i][j]+(a[r]==j)));
					dp[l][r][i][j]=max(dp[l][r][i][j],dp[l+1][r-1][i][j]+(a[r]==i)+(a[l]==j));
					dp[l][r][i][j+1]=max(dp[l][r][i][j+1],dp[l][r][i][j]);
					dp[l][r][i-1][j]=max(dp[l][r][i-1][j],dp[l][r][i][j]);
				}
			}
			for(int i=1;i<=50;i++) {
				for(int j=i;j>=1;j--) {
					dp[l][r][j-1][i]=max(dp[l][r][j-1][i],dp[l][r][j][i]);
				}
			}
		}
	}
	printf("%lld",dp[1][n][1][50]);
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值