题目来源于:洛谷
题目本质:动态规划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]);
}