• CF235C-Cyclical Quest


    题目

    开始给出母串,多次询问一个串的所有不同循环串的在母串中的出现总次数。母串长和询问总长小于等于(10^6)

    Input

    baabaabaaa
    5
    a
    ba
    baa
    aabaa
    aaba
    

    Output

    7
    5
    7
    3
    5
    

    分析

    设计到子串的问题我们可以考虑后缀自动机。

    问题就变成如何在后缀自动机中连续地匹配一个串的循环串。设需要匹配的串长为(n),我们首先把它倍长,放进自动机里匹配。如果匹配长度大于等于(n)就说明这个开头的位置匹配成功了。这时我们跳link,直到再跳一次就会令匹配长度小于(n),即当前点的出现次数就是这个循环串的出现次数,因为自动机的link相当于是在前面截掉一段。这样就可以(O(n))解决每个匹配了。关于跳link的次数,每次跳link长度都会减一,而长度最多累加到(2n),所以得到这个复杂度。

    后缀自动机的link是把前面一段截掉,这个性质很有用。

    代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int maxn=2e6+10; // 2e6+10
    const int maxc=26;
    char s[maxn];
    struct SAM {
        int t[maxn][maxc],len[maxn],link[maxn],tot,last;
        int ord[maxn],sum[maxn],tim[maxn],tic;
        bool spe[maxn];
        SAM ():tot(1),last(1),tic(0) {}
        void add(int x) {
            int nw=++tot,i;
            spe[nw]=true;
            len[nw]=len[last]+1;
            for (i=last;i && !t[i][x];i=link[i]) t[i][x]=nw;
            if (i) {
                int p=t[i][x];
                if (len[p]==len[i]+1) link[nw]=p; else {
                    int q=++tot;
                    len[q]=len[i]+1;
                    memcpy(t[q],t[p],sizeof t[p]);
                    for (int j=i;j && t[j][x]==p;j=link[j]) t[j][x]=q;
                    link[q]=link[p],link[p]=link[nw]=q;
                }
            } else link[nw]=1;
            last=nw;
        }
        void prepare() {
            for (int i=1;i<=tot;++i) ++sum[len[i]];
            for (int i=1;i<=tot;++i) sum[i]+=sum[i-1];
            for (int i=tot;i;--i) ord[sum[len[i]]--]=i;
            memset(sum,0,sizeof sum);
            for (int i=tot;i>1;--i) sum[link[ord[i]]]+=(sum[ord[i]]+=spe[ord[i]]);
            sum[0]=sum[1]=0;
        }
        int run(char s[],int n) {
            int ret=0,now=1,mat=0;
            ++tic;
            for (int i=1;i<(n<<1);++i) {
                int x=s[i]-'a';
                while (now!=1 && !t[now][x]) mat=len[now=link[now]];
                if (t[now][x]) now=t[now][x],++mat;
                while (len[link[now]]>=n) mat=len[now=link[now]];
                if (mat>=n && tim[now]!=tic) tim[now]=tic,ret+=sum[now];
            }
            return ret;
        }
    } sam;
    int main() {
    #ifndef ONLINE_JUDGE
        freopen("test.in","r",stdin);
    #endif
        scanf("%s",s+1);
        int len=strlen(s+1);
        for (int i=1;i<=len;++i) sam.add(s[i]-'a');
        sam.prepare();
        int m;
        scanf("%d",&m);
        while (m--) {
            scanf("%s",s+1),len=strlen(s+1);
            memcpy(s+len+1,s+1,(sizeof s[0])*len);
            s[len<<1|1]='';
            int ans=sam.run(s,len);
            printf("%d
    ",ans);
        }
        return 0;
    }
    
    
  • 相关阅读:
    设计模式--22、状态模式
    设计模式--21、备忘录模式
    设计模式--20、迭代器模式
    关于分布式事务、两阶段提交协议、三阶提交协议
    分布式系统的一致性探讨
    分布式系统的BASE理论
    分布式系统的CAP理论
    Kafka集群环境搭建
    Elasticsearch插件head的安装(有坑)
    centos6 x64安装elasticsearch5.5.2启动报错
  • 原文地址:https://www.cnblogs.com/owenyu/p/7140525.html
Copyright © 2020-2023  润新知