字符串与自身反串的最长公共子序列长度等于自身的最长回文子序列长度—— AT3870 [AGC021D] Reversed LCS题解
洛谷题意传送门
性质证明
题意
给你一个串 \(S\),你可以修改 \(S\) 的最多 \(k\) 个字母,然后求 \(S\) 和自身反串的最长公共子序列,求怎样修改可以使最长公共子序列最长,求最长长度。
题解
由于如标题的性质,考虑我们是怎么求最长回文子序列的,设 \(dp[l][r]\) 表示 \([l,r]\) 的最长回文子序列,那么:
\[dp[l][r]=max(dp[l][r],dp[l+1][r],dp[l][r-1])\\
dp[l][r]=max(dp[l][r],dp[l-1][r+1]+2)\,\,\,\,\,\,\,\,(st[l]==st[r])
\]
因为要修改,所以 \(dp\) 状态改成 \(dp[l][r][k]\),\(k\) 表示修改次数,就完事了。
代码
#include <bits/stdc++.h>
using namespace std ;
#define ll long long
#define rep(i,l,r) for(ll i=(l);i<=(r);++i)
#define per(i,r,l) for(ll i=(r);i>=(l);--i)
#define wif while
const ll inf = INT_MAX , df = 305 ;
ll i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,f[df][df][df] ;
char st[df] ;
int main() {
scanf( "%s" , st + 1 ) , n = strlen( st + 1 ) ;
scanf( "%lld" , &k ) ;
rep(i,1,n) f[i][i][0] = 1 ;
rep(i,2,n) {
rep(l,1,n-i+1) {
ll r = l + i - 1 ;
rep(j,0,min(r-l+1,k)) {
f[l][r][j] = max( f[l+1][r][j] , f[l][r-1][j] ) ;
if( st[l] == st[r] ) f[l][r][j] = max( f[l][r][j] , f[l+1][r-1][j] + 2 ) ;
if( j ) f[l][r][j] = max( f[l][r][j] , f[l+1][r-1][j-1] + 2 ) ;
} } }
ll ans = 0 ;
rep(i,0,k) ans = max( ans , f[1][n][i] ) ;
return printf( "%lld" , ans ) , 0 ;
}

浙公网安备 33010602011771号