给定长度为n的串S和长度为2的串T,和一个整数k,
一次操作你可以将S串中任意一个字符修改为其他字符,最多进行k次操作,
问最后S串中最多有多少个子序列T。
数据范围:n<=200,k<=n
特判一下t[1]=t[2]的情况,这时候贪心的改就行了,把s串中不等于t[1]的修改为t[1].
子序列总数就是每个s串中t[2]字符前面的t[1]数量的和.
对于修改操作,肯定是将字符修改为t[1]或者t[2],其他字符不考虑,
令d[i][j][k]表示s串前i个数,已经修改j次,t[1]有k个时的答案.
开第三维k是因为遇到t[2]的时候,需要知道前面t[1]的数量.
然后dp一下就行了,枚举是否修改以及修改为t[1]还是t[2]进行转移.
#include
using namespace std;
const int maxm=405;
int d[maxm][maxm][maxm];
char s[maxm];
char t[maxm];
int n,x;
signed main(){
cin>>n>>x;
scanf("%s",s+1);
scanf("%s",t+1);
if(t[1]==t[2]){
//特判两个字符相等的情况
int cnt=0;
for(int i=1;i<=n;i++){
if(s[i]==t[1])cnt++;
else if(x)x--,cnt++;
}
cout<<cnt*(cnt-1)/2<<endl;
return 0;
}
//init
for(int i=0;i<=n;i++){
for(int j=0;j<=x;j++){
for(int k=0;k<=i;k++){
d[i][j][k]=-1e9;
}
}
}
//dp
d[0][0][0]=0;
for(int i=0;i<n;i++){
for(int j=0;j<=i&&j<=x;j++){
for(int k=0;k<=i;k++){
if(d[i][j][k]==-1e9)continue;//非法
d[i+1][j][k]=max(d[i+1][j][k],d[i][j][k]);//不修改
if(s[i+1]==t[1]){
d[i+1][j][k+1]=max(d[i+1][j][k+1],d[i][j][k]);
}
if(s[i+1]==t[2]){
d[i+1][j][k]=max(d[i+1][j][k],d[i][j][k]+k);
}
//
if(j+1<=x){
//修改为t[1]
d[i+1][j+1][k+1]=max(d[i+1][j+1][k+1],d[i][j][k]);
}
if(j+1<=x){
//修改为t[2]
d[i+1][j+1][k]=max(d[i+1][j+1][k],d[i][j][k]+k);
}
}
}
}
//cal
int ans=0;
for(int j=0;j<=x;j++){
for(int k=0;k<=n;k++){
ans=max(ans,d[n][j][k]);
}
}
cout<<ans<<endl;
return 0;
}