• L3-020 至多删三个字符 (30 分)


    给定一个全部由小写英文字母组成的字符串,允许你至多删掉其中 3 个字符,结果可能有多少种不同的字符串?

    输入格式:

    输入在一行中给出全部由小写英文字母组成的、长度在区间 [4, 1] 内的字符串。

    输出格式:

    在一行中输出至多删掉其中 3 个字符后不同字符串的个数。

    输入样例:

    ababcc
    

    输出样例:

    25
    

    提示:

    删掉 0 个字符得到 "ababcc"。

    删掉 1 个字符得到 "babcc", "aabcc", "abbcc", "abacc" 和 "ababc"。

    删掉 2 个字符得到 "abcc", "bbcc", "bacc", "babc", "aacc", "aabc", "abbc", "abac" 和 "abab"。

    删掉 3 个字符得到 "abc", "bcc", "acc", "bbc", "bac", "bab", "aac", "aab", "abb" 和 "aba"。

    显然这道题用动态规划状态转移,无奈动态规划学的很渣,重复情况需要考虑。

    最基本的是到了第i位,删或者不删,不删表示删除个数不变,删了表示删除个数加1,以第i - 1个字符的情况为基础,创建数组dp[MAX][4],dp[i][j]表示到了第i(i >= 1)个字符,已经删了j个字符有多少字符串,我们要计算dp[i][j],考虑两种情况删或者不删,删的话,就是dp[i - 1][j - 1],表示在i - 1时删了j - 1,到了i后又删了一个一共删了j个,不删的话就是dp[i - 1][j],表示在第i - 1时就删了j个,第i个不删所以一共还是删了j个,dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j];

    但是肯定会有重复的情况,我们只需要保证,到了位置i我们清除掉他的重复情况,这样在计算后面情况时就不用考虑太多因为前面的都是没有重复的情况,要去掉重复的,只需要以前面的为基础即可。

    比如  abcdedc,显然如果删除了de和ed是一样的,都生成abcc,我们从前往后计算,到了位置6(下标从1开始),我们按照上面的式子算出了它的情况,其中dp[6][2]会包含删除ed的情况,dp[6][3]也包含删除ed但不是ded的情况即在123位置中再选一个删除,对于dp[6][2]我们需要减去什么,显然现在是删除了两个字符,删除de的情况其实就是abc一个都不删除的情况,即dp[3][0],对于dp[6][3]删除了三个字符,包含ed且不是ded也就是要减去123位置有一个字符被删除了的情况,即dp[3][1],所以对于dp[i][j],我们需要记录s[i]上一次出现的位置d d = pos[s[i]],如果d不为0,而且j - (i - d) >= 0(i - d表示什么,比如上例中ed是两个字符,i - d = 2,j减去它表示到了位置d - 1,删了几个字符),那么就dp[i][j] -= dp[d - 1][j - i + d].

    代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define MAX 1000000
    using namespace std;
    typedef long long ll;
    char s[MAX + 10];
    ll dp[MAX + 10][4];
    int pos[26];
    int main() {
        scanf("%s",s + 1);
        dp[0][0] = 1;
        int len = strlen(s + 1);
        for(int i = 1;i <= len;i ++) {
            dp[i][0] = 1;
            int d = pos[s[i] - 'a'];
            pos[s[i] - 'a'] = i;
            for(int j = 1;j < 4;j ++) {
                dp[i][j] += dp[i - 1][j - 1] + dp[i - 1][j];
                if(d && j - i + d >= 0) {
                    dp[i][j] -= dp[d - 1][j - i + d];
                }
            }
        }
        printf("%lld",dp[len][0] + dp[len][1] + dp[len][2] + dp[len][3]);
    }
  • 相关阅读:
    Dragonfly 基于 P2P 的文件和镜像分发系统
    一文搞懂 SAE 日志采集架构
    携手共建云原生生态 阿里云云原生加速器第二次集结圆满结营
    开放下载 | 飞天技术峰会云原生加速应用构建分论坛资料开放下载
    使用函数计算自定义运行时快速部署一个 SpringBoot 项目 | 文末有礼
    阿里云容器服务 ACK 产品技术动态(202207)
    阿里云 ACK One 多集群管理全面升级:多集群服务、多集群监控、两地三中心应用容灾
    掌握软件开发技术的第一性原理2
    掌握软件开发技术的第一性原理1
    library
  • 原文地址:https://www.cnblogs.com/8023spz/p/10499968.html
Copyright © 2020-2023  润新知