Atcoder AGC021 D
AGC021 D
题目大意
给一个字符串 \(s\),可以将 \(s\) 中最多 \(K\) 个字符更改为任何其他字符,使 \(s\) 和 \(s\) 的反串 \(s'\) 的最长公共子区间长度最大,输出这个长度。
题解
问题可以转化为求更改后的 \(s\) 的最长回文子序列长度。
设 \(dp(i,j,k)\) 表示区间 \([i,j]\) 已经修改了 \(k\) 个字符的最长回文子序列长度。
初始化 \(dp(i,i,0)\gets1\)。
\[dp(i,j,k)\gets\max(dp(i+1,j,k),dp(i,j-1,k))
\]
当 \(s(i)=s(j)\) 时:
\[dp(i,j,k)\gets\max(dp(i,j,k),dp(i+1,j-1,k)+2)
\]
当 \(k\neq0\) 时:
\[dp(i,j,k)\gets\max(dp(i,j,k),dp(i+1,j-1,k-1)+2)
\]
代码
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
using namespace std;
const int MAXN = 305;
char s[MAXN];
int K, dp[MAXN][MAXN][MAXN], ans;
int main()
{
scanf("%s%d", s + 1, &K);
int n = strlen(s + 1);
for (int i = 1; i <= n; i++)
{
dp[i][i][0]=1;
}
for (int m = 1; m <= n; m++)
{
for (int i = 1; i + m <= n; i++)
{
int j = i + m;
for (int k = 0; k <= K; k++)
{
dp[i][j][k] = max(dp[i + 1][j][k], dp[i][j - 1][k]);
if (s[i] == s[j])
{
dp[i][j][k] = max(dp[i][j][k], dp[i + 1][j - 1][k] + 2);
}
if (k != 0)
{
dp[i][j][k] = max(dp[i][j][k], dp[i + 1][j - 1][k - 1] + 2);
}
}
}
}
for (int i = 0; i <= K; i++)
{
ans = max(ans, dp[1][n][i]);
}
cout << ans;
return 0;
}

浙公网安备 33010602011771号