• 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;
    }
    
  • 相关阅读:
    ubuntu14.04server下安装scala+sbt工具
    如何在Ubuntu server中修改IP
    机器学习涉及到的数学知识
    Openfire+spark在linux上搭建内部聊天系统
    ubuntu14.04server版安装redis
    网站流量统计
    Visual Studio-使用vs2015 调用 vs2010编译的库时解决"无法解析的外部符号__iob_func 问题"
    书签中的一些工具整理
    android开发学习——day3
    android开发学习——day2
  • 原文地址:https://www.cnblogs.com/chd-acm/p/13664041.html
Copyright © 2020-2023  润新知