Codeforces 1409F

1409F - Subsequences of Length Two

参考博客

题意:输入两个字符串st, t串仅包含2个字符。你做多可以执行k次操作,每次可以修改s字符串中任意一个字符变成其他字符。问执行最多 k 次操作后使得ts 子序列的次数最多是多少?

题解:

  • 首先将 t[1] == t[2] 的情况处理掉:

这时肯定尽量将更多字符变成t[1], 假设最后S串中有 (num) 个t[1]字符, 答案就是 (num*(num-1) /2)


  • 下面就是 t[1] != t[2] 的处理了。

我们用dp做这道题时首先想怎么表示dp过程中的每个“状态”。显然每个状态需要表示以处理字符串位置 i,以及处理前i 个字符串使用的修改次数 j。我们各状态肯定表示的是题目要求的子序列次数的转移,但是可以发现仅现在的2个属性完全无法去进行转移时的计算。我们还需要一些其他属性。

由于本题计算子序列次数,实际就是t[2]与t[1]的匹配数,那么对每一位,如果我们知道前i - 1位的t[1]个数,那么这个dp状态转移就很好计算了,即如果当前位为t[2],那么新增贡献就是前i- 1位的t[1]字符的个数。


所以我们要用(dp[i][j][z]​) 表示当前修改第 i + 1位,且前i 修改 j 次,共有 z个t[1]时的 t作为s 子序列次数。接下来考虑dp的状态转移:

  • 首先我们可以不修改第 i + 1位。这时如果第i + 1位是t[1], 那么显然z 要 +1, 如果第i + 1位是t[2],那么贡献 + z。即:

    [dp[i+1][j][z + (s[i]==t[1])] =max(dp[i+1][j][z+(s[i]==t[1])], dp[i][j][z] + (s[i] == t[2] ? z : 0)) ]

  • 如果修改第i + 1 位为 t[1], 那么肯定z + 1, 即:

    [dp[i + 1][j + 1][z + 1] = max(dp[i + 1][j+1][z + 1], dp[i][j][z]) ]

  • 如果修改第i + 1位为 t[2], 那么肯定贡献+ z,即:

    [dp[i + 1][j + 1][z] = max(dp[i + 1][j + 1][z], dp[i][j][z] + z) ]

注意: 状态转移时,并不是dp数组表示的所有状态都合法,所以我们可以初始化dp数组为-1, 表示这个状态不合法,然后令 (dp[1][0][0] = 0) 作为开始,这样只有(dp[i][j][z]) 不为-1,即合法的状态时,采用它去更新其他状态。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e2 + 105;
const int mod = 1e9 + 7;
const double Pi = acos(- 1.0);
const int INF = 0x3f3f3f3f;
const int G = 3, Gi = 332748118;

int n, k;
char s[N], t[10];
int dp[N][N][N];

int main()
{
    scanf("%d%d",&n,&k);
    scanf("%s",s + 1);
    scanf("%s",t + 1);
    
    if(t[1] == t[2]){   //t[1] == t[2] 情况
        int num = 0;
        for(int i = 1; i <= n; ++ i){
            if(s[i] == t[1]) num ++;
        }
        num += min(k, n - num);
        printf("%d
", num * (num - 1) / 2);
        return 0;
    }
    
    memset(dp, -1, sizeof(dp));
    dp[1][0][0] = 0;
    for(int i = 1; i <= n; ++ i){
        for(int j = 0; j <= k; ++ j){
            for(int z = 0; z <= i; ++ z){
                if(dp[i][j][z] == -1) continue;
                //不修改
                dp[i + 1][j][z + (s[i] == t[1])] = max(dp[i + 1][j][z + (s[i] == t[1])], dp[i][j][z] + ((s[i] == t[2]) ? z : 0));
                //修改为t[1]
                dp[i + 1][j + 1][z + 1] = max(dp[i + 1][j + 1][z + 1], dp[i][j][z]);
                //修改为t[2]
                dp[i + 1][j + 1][z] = max(dp[i + 1][j + 1][z], dp[i][j][z] + z);
            }
        }
    }
    
    int res = 0;
    for(int j = 0; j <= k; ++ j){
        for(int z = 0; z <= n; ++ z){
            res = max(res, dp[n + 1][j][z]);
        }
    }
    printf("%d
",res);
    return 0;
}
原文地址:https://www.cnblogs.com/chd-acm/p/13664041.html