【Codeforces Round #667 (Div. 3) F】Subsequences of Length Two
题目链接
翻译
你可以把字符串 \(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;
}

浙公网安备 33010602011771号