AtCoder Grand Contest 021 D

题目链接

题意

给定一个字符串(S),允许修改其中至多(k)个字符变为(T)

(T)的反转为(T'),求(T)(T')的最长公共子序列。

题解

结论

(T)(T')的最长公共子序列的长度 = (T)的最长回文子序列的长度

证明

part. 1

先证:(T)(T')的最长公共子序列的长度(leq T)的最长回文子序列的长度

假设(LCS)的长度为(k),则存在(i_1<cdots <i_k)(j_1>cdots >j_k)使得(T_{i_1},T_{i_2},cdots,T_{i_k})(T_{j_1},T_{j_2},cdots,T_{j_k})是相同的。

则必(exists p,i_p<j_p)(i_{p+1}geq j_{p+1}).(方便起见,记(i_{k+1}=|T|+1,j_{k+1}=-1).)

  1. (i_{p+1}>j_{p+1}),则序列(T_{i_1},cdots,T_{i_p},T_{j_p},cdots,T_{j_1})和序列(T_{j_k},cdots,T_{j_{p+1}},T_{i_{p+1}},cdots,T_{i_k})都是回文串,并且长度和为(2k). 因此,(T)含有一个长度至少为(k)的回文子序列;
  2. (i_{p+1}=j_{p+1}),则序列(T_{i_1},cdots,T_{i_p},T_{i_{p+1}},T_{j_p},cdots,T_{j_1})和序列(T_{j_k},cdots,T_{j_{p+2}},T_{j_{p+1}},T_{i_{p+2}},cdots,T_{i_k})都是回文串,并且长度和为(2k). 因此,(T)含有一个长度至少为(k)的回文子序列。

part. 2

再证:(T)(T')的最长公共子序列的长度(geq T)的最长回文子序列的长度

假设(T)的最长回文子序列长为(k),则存在(i_1<cdots <i_k)使(T_{i_1},cdots,T_{i_k})为回文子序列。

(j_1=n-i_k+1,cdots,j_k=n-i_1+1),则(T'_{j_1}=T{i_k}=T{i_1},cdots,T'{j_k}=T{i_1}=T{i_k}),即(T_{i_1},cdots,T_{i_k})(T'_{j_1},cdots,T'{j_k})相等,即为(T)(T')的公共子序列。

因此,(T)(T')的公共子序列长度至少为(k).

总结

综上,(T)(T')(LCS)的长度 = (T)的最长回文子序列的长度。

dp

根据上面的结论,问题就转化成了:
对于给定的字符串(S),修改不超过(k)个字符,使得其最长回文子序列取到最长。

(dp[l][r][x])表示(s[l..r])修改至多(x)个字符后的最长回文子序列的长度。

时间复杂度:(O(N^3)).

Code

#include <bits/stdc++.h>
#define F(i, a, b) for (int i = (a); i < (b); ++i)
#define F2(i, a, b) for (int i = (a); i <= (b); ++i)
#define dF(i, a, b) for (int i = (a); i > (b); --i)
#define dF2(i, a, b) for (int i = (a); i >= (b); --i)
#define maxn 310
using namespace std;
typedef long long LL;
char ss[maxn];
int dp[maxn][maxn][maxn];
int main() {
    int k;
    scanf("%s%d", ss, &k);
    int n = strlen(ss), ans=0;
    dF2(l, n-1, 0) {
        F(r, l, n) {
            F2(x, 0, k) {
                if (ss[l]==ss[r]) dp[l][r][x] = dp[l+1][r-1][x]+(l==r?1:2);
                else {
                    dp[l][r][x] = max(dp[l+1][r][x], dp[l][r-1][x]);
                    if (x) dp[l][r][x] = max(dp[l][r][x], dp[l+1][r-1][x-1]+2);
                }
            }
        }
    }
    printf("%d
", dp[0][n-1][k]);
    return 0;
}

原文地址:https://www.cnblogs.com/kkkkahlua/p/8470931.html