【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;
}
posted @ 2020-09-12 20:15  AWCXV  阅读(160)  评论(0)    收藏  举报