题目链接
翻译
你可以把字符串 (s) 中的某个字符改成任意一个字符最多 (k) 次,这样做之后,问你最后形成的 (s) 中最多会有多少个 (t) 子序列。
题解
设 (f[i][j][l]) 表示前 (i) 个字符,修改了 (j) 次, 有 (l) 个 (t[1]) 字符, (t) 作为子序列最多出现的次数。
假设已经求得了前 (i) 个字符的最优值。
第 (i+1) 个字符有三种情况:
- 不变
- 变成 (t[1])
- 变成 (t[2])
然后如果新增了一个 (t[2]),那么显然答案就递增 (l), 也即前面的 (t[1]) 的个数。
注意 (t[1]) 是有可能等于 (t[2]) 的, 所以新增 (t[1]) 也是可能会递增答案的,转移的时候要注意这一点。
具体的转移看代码吧:)
最后在 (f[n][0..k][0..n]) 里面找答案就好。
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 200;
//f[i][j][l] 表示前 i 个字符,修改了 j 次, 有 l 个 t[1] 字符, t 作为子序列最多出现的次数。
int n, k, f[N + 10][N + 10][N + 10];
char s[N + 10],t[N + 10];
int fmax(int a,int b){
if (a == -1){
return b;
}else {
return max(a,b);
}
}
int main(){
#ifdef LOCAL_DEFINE
freopen("E://9.AlgorithmCompetition//Visitor.txt","r",stdin);
#endif
ios::sync_with_stdio(0),cin.tie(0);
cin >> n >> k;
cin >> (s+1);
cin >> (t+1);
memset(f,255,sizeof(f));
f[0][0][0] = 0;
for (int i = 0;i < n; i++){
for (int j = 0;j <= k; j++){
for (int l = 0;l <= i;l++){
if (f[i][j][l] >= 0){
// i+1
//unchanged
f[i+1][j][l+(s[i+1]==t[1])] = fmax(f[i+1][j][l+(s[i+1]==t[1])],f[i][j][l]+(s[i+1]==t[2])*l);
//change into t[1]
f[i+1][j+1][l+1] = fmax(f[i+1][j+1][l+1],f[i][j][l]+(t[1]==t[2])*l);
//change into t[2]
f[i+1][j+1][l+(t[1]==t[2])] = fmax(f[i+1][j+1][l+(t[1]==t[2])],f[i][j][l] + l);
}
}
}
}
int ans = 0;
for (int j = 0;j <= k; j++){
for (int l = 0;l <= n;l++){
ans = max(f[n][j][l],ans);
}
}
cout << ans << endl;
return 0;
}