• CF578D. LCS Again


    n<=100000个字符的小写字母串,问用前m<=26个小写字母能拼出多少个和原串lcs=n-1的字符串。

    首先把字符串划分成若干个连续相同的段,如aaa|bb|c|dd,然后题目即要求从里面挖掉一个再丢回去一个。如挖掉a,那么就剩aa|bb|c|dd,可以发现一个连续相同段挖谁都一样所以一个连续相同段只算一次,然后补一个。可以发现在自己的相同段中不能丢一个和原来一样的,而在其他地方同一个字母前后丢一样的会算重,如aab b bcdd,和aabb b cdd,也就是在第二个b前后丢b效果相同,所以每个地方只能放m-1个字符,就加上n*(m-1)。

    然而还会算重。。比如ababab这样的连续段,任意挖一个补到后面一定对应一个后面补到前面的方案,比如这里把第一个a补到最后变成bababa,和把最后一个b提到最前是一样的。假设有一段连续的abab……串长度len,那么他有len*(len-1)/2个abab……的子串,就减掉即可。

     1 #include<stdio.h>
     2 #include<string.h>
     3 #include<stdlib.h>
     4 #include<algorithm>
     5 //#include<iostream>
     6 using namespace std;
     7 
     8 int n,m;
     9 #define maxn 200011
    10 char s[maxn];
    11 
    12 int main()
    13 {
    14     scanf("%d%d",&n,&m);
    15     scanf("%s",s+1);
    16     #define LL long long
    17     LL ans=n*(m-1);
    18     for (int i=2;i<=n;i++) if (s[i]!=s[i-1]) ans+=n*(m-1);
    19     int len=1;
    20     for (int i=2;i<=n;i++)
    21     {
    22         if (len==1) if (s[i-1]!=s[i]) len++;else{}
    23         else if (s[i-2]==s[i]) len++;
    24         else
    25         {
    26             ans-=1ll*len*(len-1)/2;
    27             if (s[i]==s[i-1]) len=1;
    28             else len=2;
    29         }
    30     }
    31     ans-=1ll*len*(len-1)/2;
    32     printf("%lld
    ",ans);
    33     return 0;
    34 }
    View Code

    YYL的做法:

    关注这种匹配方式的开始条件和结尾条件,即每个位置作为斜线区域开始的方案数,作为终止区域结束的方案数。需要分个类:

    这里a!=b会有1的开始位置贡献。

    这里若a=b,d会有m-1种结束方式;若a!=b,d会有m-2种结束方式。

    待填坑。

  • 相关阅读:
    在 Laravel 5.1 中使用 Pjax
    在 iOS 中实现方法链调用
    利用 WireShark 深入调试网络请求
    设计一个健壮的后台下载
    设计一个健壮的大型文件下载系统
    iOS开发基础知识:Core Animation(核心动画)
    开发 Swift 和 Objective-C 混编的 Framework
    protobuf3 iOS 接入 protobuf
    iOS之ProtocolBuffer搭建
    iOS10 推送必看(基础篇)
  • 原文地址:https://www.cnblogs.com/Blue233333/p/8007038.html
Copyright © 2020-2023  润新知