zoukankan      html  css  js  c++  java
  • CF 578D LCS Again 简要题解

    私以为很巧妙的一道计数题

    (不会正经的dp做法)


    题意:给一个长度为n,仅包含前m个小写字母的字符串S,求有多少个字符串由前m个小写字母构成的T,满足LCS(S,T) == n - 1

    n <= 1e5,2 <= m <= 26

    我们考虑枚举LCS,容易发现一定是S去掉某个字母得到的,又因为去掉连续一段的字母中的任何一个都一样,所以LCS有(S的连续段数个)

    eg:aaabcccdd,删掉第1个a,删掉第2个a,得到的LCS显然相同,所以LCS有4个

    考虑删完后如何插入一个字母.我们不妨强行设去掉的那个字母在删除的最前段.为避免重复,我们可以令添加后的字符在连续段内的第一个,即添加的字符不能和前面的一个字符相同

    所以方案数有(n - 1) * (m - 1) + m - 1 = n * (m - 1) ;

    后面的+m是因为第一个空位前面没有字符,可以插m个,-1是因为我们插的字符如果在删去的字符的位置,不能和删去的字符相同,否则LCS = n

    有人可能会问:那会不会出现删去的字符和前一个字符相同所以多减一遍之类的鬼畜情况?

    所以我们强行设去掉的那个字母在删除的最前端.这样就不会了.

    所以ans = 段数 * n * (m - 1)???

    如果你这样发现连样例都过不了

    考虑以下情况 /s/ /str/ /t/ 

    发生以下两种移位 /s/ /t/ /str/

    /str/ /s/ /t/

    易发现如果/str/的循环同构循环节恰好为2,会算重一次.所以答案还要减掉所有循环节为2的子串即abab....ab之类的

    代码如下

    /*CF578D LCS Again*/
    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    int read(){
        char c = getchar();
        int x = 0;
        while(c < '0' || c > '9')        c = getchar();
        while(c >= '0' && c <= '9')        x = x * 10 + c - 48,c = getchar();
        return x;
    }
    const int N = 1e5 + 10;
    char s[N];
    int main(){
        int n = read(),m = read();
        scanf("%s",s+1);
        ll ans = 0;
        for(int i = 1; i <= n; ++i){
            if(s[i] != s[i-1])    ans += 1ll * n * (m - 1);
        }
        int len = 1;
        for(int i = 2; i <= n; ++i){
            if(len == 1){
                if(s[i] == s[i-1])    continue;
                else    len++;
            }
            else if(s[i] == s[i-2]){
                len++;
            }
            else{
                ans -= 1ll * len * (len - 1) / 2;
                if(s[i] == s[i-1])    len = 1;
                else    len = 2;
            }
        }
        ans -= 1ll * len * (len - 1) / 2;
        cout<<ans<<endl;
        return 0;
    }

    思考下我们做了什么(本sb想这题花了两个晚上)

    首先分析题目的性质,找到LCS

     然后便是一步步去重.该约束条件很简洁,让我们有办法直接做,直接去重

    不然可能要进一步分析,找到更简洁的充要条件(比如本题本质不同的LCS要考虑段数之类的)

  • 相关阅读:
    域名解析速度好快了。
    ASP生成图形(数字验证码)
    PHP过滤字符
    “树人杯”暨第三届辽宁科技大学校园程序设计竞赛正赛F 最后一个是谁?(紫)
    “树人杯”暨第三届辽宁科技大学校园程序设计竞赛正赛G 又是一个小游戏(蓝)
    面试题06 判断二叉树后序遍历的结果 [树]
    [acm] 动态规划相关的题目 [ 个人 ]
    [面试备] 暴搜 or 二分图的经典升级 : hdu 1045 Fire Net 示例 [ 二分图 ]
    面试题02 从上往下打印二叉树 【树】[ water ]
    面试题05 树的子结构 [树]
  • 原文地址:https://www.cnblogs.com/y-dove/p/14274410.html
Copyright © 2011-2022 走看看