zoukankan      html  css  js  c++  java
  • 循环移位(后缀自动机)

    题目描述:

    给定一个字符串 s 。现在问你有多少个本质不同的 s 的子串 t=tt⋯ t(m>0使得将 t 循环左移一位后变成的 t=t⋯ tt1 也是 s 的一个子串。

    题解:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N=300010;
    char s[N];
    int n,lst=1,tot=1;
    int len[N*2],ch[N*2][26],fa[N*2],pos[N*2];
    //pos表示在原串中的位置
    int sum[N][26];
    ll ans;
    void add(int c){
        int p=lst,np=lst=++tot;
        pos[np]=len[np]=len[p]+1;
        for(;p&&!ch[p][c];p=fa[p]) ch[p][c]=np;
        if(!p) fa[np]=1;
        else{
            int q=ch[p][c];
            if(len[q]==len[p]+1) fa[np]=q;
            else{
                int nq=++tot;
                memcpy(ch[nq],ch[q],sizeof(ch[q]));
                fa[nq]=fa[q];
                len[nq]=len[p]+1;
                pos[nq]=pos[q];
                fa[q]=fa[np]=nq;
                for(;p&&ch[p][c]==q;p=fa[p]) ch[p][c]=nq;
            }
        }
        return;
    }
    int main(){
        scanf("%s",s+1);
        n=strlen(s+1);
        for(int i=1;i<=n;i++)
            add(s[i]-'a');
        for(int i=1;i<=n;i++)
            for(int j=0;j<26;j++)
                sum[i][j]=sum[i-1][j]+(s[i]-'a'==j);
        for(int i=2;i<=tot;i++){
            if(ch[fa[i]][s[pos[i]-len[fa[i]]]-'a'])
                ans++;
            for(int j=0;j<26;j++)
                if(ch[i][j])
                    ans+=sum[pos[i]-len[fa[i]]-1][j]-sum[pos[i]-len[i]][j];
        }
        printf("%lld",ans);
        return 0;
    }

    好了我知道这个不好懂,所以我们再配张图:

  • 相关阅读:
    Codeforces Round #398 (Div. 2) B,C
    KMP模板
    HDU1711 KMP(模板题)
    HDU3265 线段树(扫描线)
    HDU2795 线段树
    HDU1828线段树(扫描线)
    HDU1832 二维线段树求最值(模板)
    HDU1698 线段树(区间更新区间查询)
    HDU3251 最大流(最小割)
    cf2.c
  • 原文地址:https://www.cnblogs.com/HarryPotter-fan/p/11385786.html
Copyright © 2011-2022 走看看