zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    9月16日 星期二 晴
    谁能联系到小爱
    初学者请教Reporting Service达人,小女给能够进来看一眼的好心人抱拳一拜
    9月19日 多云
    iPhone开发教程之Core Data 常见问题的总结
    移动终端开发必备知识
    Core Data 教程(3): 入门指南
    【转载】APK反破解之四:Android代码动态加载技术
    REST是什么
    (转载)设计师必备工具推荐(上)【译】
  • 原文地址:https://www.cnblogs.com/chd-acm/p/13664041.html
Copyright © 2011-2022 走看看