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;
}
posted @ 2021-01-30 20:44  cymrain07  阅读(49)  评论(0)    收藏  举报
\