• LG P7114 字符串匹配


    Description

    小 C 学习完了字符串匹配的相关内容,现在他正在做一道习题。

    对于一个字符串 $S$,题目要求他找到 $S$ 的所有具有下列形式的拆分方案数:

    $S = ABC$,$S = ABABC$,$S = ABAB ldots ABC$,其中 $A$,$B$,$C$ 均是非空字符串,且 $A$ 中出现奇数次的字符数量不超过 $C$ 中出现奇数次的字符数量。

    更具体地,我们可以定义 $AB$ 表示两个字符串 $A$,$B$ 相连接,例如 $A = exttt{aab}$,$B = exttt{ab}$,则 $AB = exttt{aabab}$。

    并递归地定义 $A^1=A$,$A^n = A^{n - 1} A$($n ge 2$ 且为正整数)。例如 $A = exttt{abb}$,则 $A^3= exttt{abbabbabb}$。

    则小 C 的习题是求 $S = {(AB)}^iC$ 的方案数,其中 $F(A) le F(C)$,$F(S)$ 表示字符串 $S$ 中出现奇数次的字符的数量。两种方案不同当且仅当拆分出的 $A$、$B$、$C$ 中有至少一个字符串不同。

    小 C 并不会做这道题,只好向你求助,请你帮帮他。

    Solution

    预处理每个前缀和后缀的奇数字符个数

    枚举$AB$的数次方,检验时使用哈希,每次对答案的贡献为$(AB)^i$可以被分成使$A$满足要求的方案数

    时间复杂度$O(n log n)$,勉强能过,使用exKMP可以达到$O(n)$,不会

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    using namespace std;
    short T,pre[1050005],suf[1050005],buc[30];
    int n,vst[30];
    long long ans;
    unsigned long long base[1050005]={1},has[1050005];
    char s[1050005];
    inline int read()
    {
        int f=1,w=0;
        char ch=0;
        while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9') w=(w<<1)+(w<<3)+ch-'0',ch=getchar();
        return f*w;
    }
    int main()
    {
        T=read();
        for(int i=1;i<=1050000;i++) base[i]=base[i-1]*31;
        for(;T;T--)
        {
            scanf("%s",s+1),n=strlen(s+1),ans=0;
            memset(buc,0,sizeof(buc)),memset(vst,0,sizeof(vst)),memset(suf,0,sizeof(suf));
            for(int i=1;i<=n;i++)
            {
                buc[s[i]-'a']^=1;
                if(buc[s[i]-'a']) pre[i]=pre[i-1]+1;
                else pre[i]=pre[i-1]-1;
            }
            memset(buc,0,sizeof(buc));
            for(int i=n;i;i--)
            {
                buc[s[i]-'a']^=1;
                if(buc[s[i]-'a']) suf[i]=suf[i+1]+1;
                else suf[i]=suf[i+1]-1;
            }
            for(int i=1;i<=n;i++) has[i]=has[i-1]*31+1ull*(s[i]-'a');
            for(int i=2;i<=n;i++)
            {
                for(int j=pre[i-1];j<=26;j++) vst[j]++;
                for(int j=i;j<n&&has[i]==has[j]-has[j-i]*base[i];j+=i) ans+=vst[suf[j+1]];
            }
            printf("%lld
    ",ans);
        }
        return 0;
    }
    字符串匹配
  • 相关阅读:
    步步为营 .NET 设计模式学习笔记 十三、Bridge (桥接模式)
    步步为营 .NET 设计模式学习笔记 十五、Composite(组合模式)
    Web服务器及客户端软件推荐
    步步为营 .NET 代码重构学习笔记 二、提炼方法(Extract Method)
    步步为营 .NET 代码重构学习笔记 十
    步步为营 .NET 设计模式学习笔记 十、Builder(建造者模式)
    步步为营 .NET 代码重构学习笔记 八
    新浪微博的文字滚动更新效果
    几段javascript实现一个打字游戏效果
    jquery实现简单的手风琴效果
  • 原文地址:https://www.cnblogs.com/JDFZ-ZZ/p/14131478.html
Copyright © 2020-2023  润新知