【[USACO17JAN]Subsequence Reversal P】题解
前言
希望审核能给我过了这篇题解 。
题目
题目传送门
正文
很巧妙的思维题啊 , 一开始丝毫没有思路 , 瞟了一眼题解 , 看到一句话 : 交换一个序列相当于不相交的交换几个元素 , 因为这几个元素交换之后就相当于是交换了一个子序列 。
有了这句话的提示 , 问题就迎刃而解了 , 关键要做到交换的元素不能相交 , 其实只需要 DP 的顺序没问题即可 , 那么显然假设 [L,R] 已经解决了 , 那么交换的元素就强制只能在 [L,R] 之外 。
下面正式开始 DP , 定义
不交换的转移 :
交换的转移 :
注意值域是可以向两边扩展的 。
AC code :
#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]);
}