字符串与自身反串的最长公共子序列长度等于自身的最长回文子序列长度—— 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 ;
}
posted @ 2021-08-27 15:59  red_giant_bear  阅读(72)  评论(0)    收藏  举报