zoukankan      html  css  js  c++  java
  • 字符串题目

     回文自动机  马拉车 后缀自动机  后缀数组  AC自动机  EXKMP  KMP  字典树  字符串匹配shiftand算法  字符串哈希   

     手写哈希

    #include<bits/stdc++.h>
    using namespace std;
    struct Hash {
        static const int MOD = 1999997;
        static const int N = 1e6;
        int head[MOD + 10], nx[N], top;
        int hs[N], id[N];
        void init() {
            memset(head, -1, sizeof head);
            top = 0;
        }
        void insert(int x, int y) {
            int k = x % MOD;
            hs[top] = x; id[top] = y; nx[top] = head[k]; head[k] = top++;
        }
        int find(int x) {
            int k = x % MOD;
            for (int i = head[k]; i != -1; i = nx[i]) {
                if (hs[i] == x) {
                    return id[i];
                }
            }
            return -1;
        }
    }hs;
    int main(){   }
    
    hash
    View Code

    回文自动机模板

    #include<bits/stdc++.h>
    using namespace std;
    struct PAM{
        #define ll long long
        #define LL long long
        static const int maxn=3e5+10;
        static const int num=27;
        char ss[maxn];  int c=0;
        int fail[maxn],cnt[maxn],len[maxn],ch[maxn][num];
        int last,tot;
        //LL ans;
        void inint(){
            c=0;
            last=0;  tot=0;
            fail[0]=fail[1]=1;
            len[0]=0; len[1]=-1; tot++;
        }
        int get_fail(int p,int pos){
             while(ss[pos-len[p]-1]!=ss[pos]) p=fail[p];
             return p;
        }
        void add(int x,int pos){
            ss[c]='a'+x;  c++;
            int p=get_fail(last,pos);
            if(!ch[p][x]){
                len[++tot]=len[p]+2;
                fail[tot]=ch[get_fail(fail[p],pos)][x];
                ch[p][x]=tot; //ans++;
            }
            cnt[last=ch[p][x]]++;
        }
        void clear(){
            for(int i=0;i<=tot;i++){
                fail[i]=0; len[i]=0; cnt[i]=0;
                for(int j=0;j<num;j++) ch[i][j]=0;
            }
            last=tot=ans=0;
        }
    }pam;
    const int maxn=1e5+10;
    char ss[maxn];
    int main(){
    
    }
    回文自动机

    回文自动机   本质不同回文串个数   tot-1;

    #include<bits/stdc++.h>
    #define ll long long
    #define LL long long
    using namespace std;
    const int maxn=2e5+10;
    const int num=26;
    char ss[maxn];
    int fail[maxn],cnt[maxn],len[maxn],ch[maxn][num];
    struct PAM{
        int last,tot;
        ll ans;
        void inint(){
            last=0;  tot=0;
            fail[0]=fail[1]=1;
            len[0]=0; len[1]=-1; tot++;
        }
        int get_fail(int p,int pos){
             while(ss[pos-len[p]-1]!=ss[pos]) p=fail[p];
             return p;
        }
        void add(int x,int pos){
            int p=get_fail(last,pos);
            if(!ch[p][x]){
                len[++tot]=len[p]+2;
                fail[tot]=ch[get_fail(fail[p],pos)][x];
                ch[p][x]=tot;
            }
            cnt[last=ch[p][x]]++;
        }
        void count(){  //  bu zhi bu tong hui wen ge shu
            for(int i=tot;i>=0;i--){
                cnt[fail[i]]+=cnt[i];
                cnt[fail[i]]%=51123987;
            }
        }
        ll count_tot(){
            ll w=0; count();
            for(int i=2;i<=tot;i++) w+=cnt[i];
            return w;
        }
        void clear(){
            for(int i=0;i<=tot;i++){
                fail[i]=0; len[i]=0; cnt[i]=0;
                for(int j=0;j<num;j++) ch[i][j]=0;
            }
            last=tot=ans=0;
        }
    }pam;
    int main(){
        //int x; scanf("%d",&x);
        scanf("%s",ss);
        int l=strlen(ss); pam.inint();
        for(int i=0;i<l;i++) {
            pam.add(ss[i]-'a',i);
            if(i!=0) printf(" ");
            printf("%d",pam.tot-1);
        }
    }
    View Code

     回文自动机  字符串l-r  区间本质不同回文串个数    

    #include<bits/stdc++.h>
    #define ll long long
    #define LL long long
    using namespace std;
    const int maxn=1010;
    struct PAM{
        static const int maxn=1e3+10;
        static const int num=26;
        char ss[maxn];  int c=0;
        int fail[maxn],cnt[maxn],len[maxn],ch[maxn][num];
        int last,tot;
        ll ans;
        void inint(){
            last=0;  tot=0; c=0;
            fail[0]=fail[1]=1;
            len[0]=0; len[1]=-1; tot++;
        }
        int get_fail(int p,int pos){
             while(ss[pos-len[p]-1]!=ss[pos]) p=fail[p];
             return p;
        }
        void add(int x,int pos){
            ss[c++]=x+'a';
            int p=get_fail(last,pos);
            if(!ch[p][x]){
                len[++tot]=len[p]+2;
                fail[tot]=ch[get_fail(fail[p],pos)][x];
                ch[p][x]=tot;
            }
            cnt[last=ch[p][x]]++;
        }
        void clear(){
            for(int i=0;i<=tot;i++){
                fail[i]=0; len[i]=0; cnt[i]=0;
                for(int j=0;j<num;j++) ch[i][j]=0;
            }
            last=tot=ans=0; c=0;
        }
    }pam;
    char ss[maxn];
    int a[maxn][maxn];
    int main(){
        int T; scanf("%d",&T);
        while(T--){
            scanf("%s",ss);
            int q; scanf("%d",&q);
            int n=strlen(ss);
            for(int i=0;i<n;i++){
                pam.clear();
                pam.inint();
                for(int j=i;j<n;j++){
                    pam.add(ss[j]-'a',j-i);
                    a[i][j]=pam.tot-1;
                }
            }
            while(q--){
                int l,r; scanf("%d %d",&l,&r);
                printf("%d
    ",a[l-1][r-1]);
            }
        }
    }
    Vbuiew Code

     回文自动机   回文串权值问题

    #include<bits/stdc++.h>
    #define ll long long
    #define LL long long
    using namespace std;
    const int maxn=1010000;
    struct PAM{
        static const int maxn=3e5+10;
        static const int num=26;
        char ss[maxn];  int c=0;
        int fail[maxn],cnt[maxn],len[maxn],ch[maxn][num];
        int last,tot;
        ll ans=0;
        void inint(){
            last=0;  tot=0; c=0; ans=0;
            fail[0]=fail[1]=1;
            len[0]=0; len[1]=-1; tot++;
        }
        int get_fail(int p,int pos){
             while(ss[pos-len[p]-1]!=ss[pos]) p=fail[p];
             return p;
        }
        void add(int x,int pos){
            ss[c++]=x+'a';
            int p=get_fail(last,pos);
            if(!ch[p][x]){
                len[++tot]=len[p]+2;
                fail[tot]=ch[get_fail(fail[p],pos)][x];
                ch[p][x]=tot;
            }
            cnt[last=ch[p][x]]++;
        }
        void  dfs(int x){
            for(int i=0;i<num;i++){
                if(ch[x][i]){
                    int w=ch[x][i];
                    //cout<<w<<" "<<cnt[w]<<" "<<len[w]<<endl;
                    ans=max(1ll*cnt[w]*len[w],ans);
                    dfs(w);
                }
            }
    
        }
        ll slove(){
            for(int i=tot;i>=0;i--) cnt[fail[i]]+=cnt[i];
            dfs(1);  dfs(0);
            return ans;
        }
        void clear(){
            for(int i=0;i<=tot;i++){
                fail[i]=0; len[i]=0; cnt[i]=0;
                for(int j=0;j<num;j++) ch[i][j]=0;
            }
            last=tot=ans=0; c=0;
        }
    }pam;
    char ss[maxn];
    int a[maxn][maxn];
    int main(){
        scanf("%s",ss);
        pam.inint();
        int n=strlen(ss);
        for(int i=0;i<n;i++){
            pam.add(ss[i]-'a',i);
        }
        printf("%lld
    ",pam.slove());
    }
    View Code

     hdu 5394  回文自动机上删点 加点操作  回文自动机上记忆化搜索

    #pragma comment(linker, "/STACK:1024000000,1024000000")
    #include<iostream>
    #include<vector>
    #include<stdio.h>
    #include<math.h>
    using namespace std;
    struct PAM{
        #define ll long long
        #define LL long long
        static const int maxn=2e6+10;
        static const int num=27;
        char ss[maxn];
        int relast[maxn];
        int  retot[maxn];
        ll   sum[maxn];
        bool check[maxn];
        int c=0;
        int fail[maxn],cnt[maxn],len[maxn],ch[maxn][num];
        int last,tot;
        void inint(){
            c=0;
            last=0;  tot=0;
            fail[0]=fail[1]=1;
            len[0]=0; len[1]=-1; tot++;
        }
        int get_fail(int p,int pos){
             while(ss[pos-len[p]-1]!=ss[pos]) p=fail[p];
             return p;
        }
        void add(int x,int pos){
            ss[c]='a'+x;  c++;
            relast[pos]=last;//
            retot[pos]=tot;//
            int p=get_fail(last,pos);
            if(!ch[p][x]){
                check[pos]=1;//
                len[++tot]=len[p]+2;
                fail[tot]=ch[get_fail(fail[p],pos)][x];
                ch[p][x]=tot;
            }
            cnt[last=ch[p][x]]++;
    
        }
        void re(int x,int pos){
            c--;
            last=relast[pos];
            tot=retot[pos];
            int p=get_fail(last,pos);
            if(check[pos]==1){
                check[pos]=0;
                len[++tot]=0;
                fail[tot]=0;
                ch[p][x]=0;
                sum[tot]=0;
            }
            cnt[last=ch[p][x]]--;
            last=relast[pos]; tot=retot[pos];
            relast[pos]=0; retot[pos]=0;
        }
        ll dfs(int x){
    
            if(x==0 || x==1) return 0;
            if(sum[x]!=0) return sum[x];
            return  sum[x]=dfs(fail[x])+len[x];
        }
        ll work(){
           return dfs(last);
        }
    
    }pam;
    #define ll long long
    const int maxn=2e6+10;
    //char ss[maxn];
    ll ans=0;
    vector<pair<int,char> > vs[maxn];
    void dfs(int x,int tot){
        for(int i=0;i<vs[x].size();i++){
    
            pam.add(vs[x][i].second,tot);
            ans+=pam.work();
    
            dfs(vs[x][i].first,tot+1);
            pam.re(vs[x][i].second,tot);
        }
    }
    struct FastIO {
        static const int S = 4e6;
        int wpos;
        char wbuf[S];
        FastIO() : wpos(0) {}
        inline int xchar() {
            static char buf[S];
            static int len = 0, pos = 0;
            if (pos == len)
                pos = 0, len = fread(buf, 1, S, stdin);
            if (pos == len) exit(0);
            return buf[pos++];
        }
        inline int xuint() {
            int c = xchar(), x = 0;
            while (c <= 32) c = xchar();
            for (; '0' <= c && c <= '9'; c = xchar()) x = x * 10 + c - '0';
            return x;
        }
        inline int xint()
        {
            int s = 1, c = xchar(), x = 0;
            while (c <= 32) c = xchar();
            if (c == '-') s = -1, c = xchar();
            for (; '0' <= c && c <= '9'; c = xchar()) x = x * 10 + c - '0';
            return x * s;
        }
        inline void xstring(char *s)
        {
            int c = xchar();
            while (c <= 32) c = xchar();
            for (; c > 32; c = xchar()) * s++ = c;
            *s = 0;
        }
        inline void wchar(int x)
        {
            if (wpos == S) fwrite(wbuf, 1, S, stdout), wpos = 0;
            wbuf[wpos++] = x;
        }
        inline void wint(int x)
        {
            if (x < 0) wchar('-'), x = -x;
            char s[24];
            int n = 0;
            while (x || !n) s[n++] = '0' + x % 10, x /= 10;
            while (n--) wchar(s[n]);
            wchar('
    ');
        }
        inline void wstring(const char *s)
        {
            while (*s) wchar(*s++);
        }
        ~FastIO()
        {
            if (wpos) fwrite(wbuf, 1, wpos, stdout), wpos = 0;
        }
    } io;
    int main(){
        int T;
         T=io.xint();
        //cin>>T;
        while(T--){
            pam.inint();
            ans=0;
            int n;
            n=io.xint();
            //cin>>n;
            for(int i=1;i<=n;i++){
                char x; int y;
                x=io.xchar();
                y=io.xint();
                //cin>>x>>y;
                vs[y].push_back({i,x});
            }
            dfs(0,0);
            printf("%lld
    ",ans);
            for(int i=0;i<=n;i++) vs[i].clear();
           // pam.clear();
        }
    }
    View Code

     洛谷  最长双回文串

    #include<bits/stdc++.h>
    using namespace std;
    struct PAM{
        #define ll long long
        #define LL long long
        static const int maxn=3e5+10;
        static const int num=27;
        char ss[maxn];  int c=0;
        int fail[maxn],cnt[maxn],len[maxn],ch[maxn][num];
        int last,tot;
        LL ans;
        void inint(){
            c=0;
            last=0;  tot=0;
            fail[0]=fail[1]=1;
            len[0]=0; len[1]=-1; tot++;
        }
        int get_fail(int p,int pos){
             while(ss[pos-len[p]-1]!=ss[pos]) p=fail[p];
             return p;
        }
        void add(int x,int pos){
            ss[c]='a'+x;  c++;
            int p=get_fail(last,pos);
            if(!ch[p][x]){
                len[++tot]=len[p]+2;
                fail[tot]=ch[get_fail(fail[p],pos)][x];
                ch[p][x]=tot; ans++;
            }
            cnt[last=ch[p][x]]++;
        }
        int work(){
            return len[last];
        }
        void clear(){
            for(int i=0;i<=tot;i++){
                fail[i]=0; len[i]=0; cnt[i]=0;
                for(int j=0;j<num;j++) ch[i][j]=0;
            }
            last=tot=ans=0;
        }
    }pam;
    const int maxn=2e5+10;
    char ss[maxn];
    int ans[maxn];
    int main(){
        scanf("%s",ss);  int l=strlen(ss);
        pam.inint();
        for(int i=0;i<l;i++){
            pam.add(ss[i],i);
            ans[i]+=pam.work();
    
        }
        pam.clear();
        pam.inint();
        for(int i=l-1;i>=0;i--){
            pam.add(ss[i],l-1-i);
            if(i-1>=0) ans[i-1]+=pam.work();
        }
        int x=0;
        for(int i=1;i<l-1;i++){
            x=max(ans[i],x);
        }
        printf("%d
    ",x);
    
    }
    View Code

     洛谷  拉拉队排练

    #include<bits/stdc++.h>
    using namespace std;
    int numm[2000005];
    struct PAM{
        #define ll long long
        #define LL long long
        static const int maxn=2e6+10;
        static const int num=27;
        char ss[maxn];  int c=0;
        int fail[maxn],cnt[maxn],len[maxn],ch[maxn][num];
        int last,tot;
        LL ans;
        void inint(){
            c=0;
            last=0;  tot=0;
            fail[0]=fail[1]=1;
            len[0]=0; len[1]=-1; tot++;
        }
        int get_fail(int p,int pos){
             while(ss[pos-len[p]-1]!=ss[pos]) p=fail[p];
             return p;
        }
        void add(int x,int pos){
            ss[c]='a'+x;  c++;
            int p=get_fail(last,pos);
            if(!ch[p][x]){
                len[++tot]=len[p]+2;
                fail[tot]=ch[get_fail(fail[p],pos)][x];
                ch[p][x]=tot; ans++;
            }
            cnt[last=ch[p][x]]++;
        }
        void count(){
            for(int i=tot;i>=2;i--){
                cnt[fail[i]]+=cnt[i];
                if(len[i]%2==1){
                    numm[len[i]]+=cnt[i];
                }
            }
    
    
        }
        void clear(){
            for(int i=0;i<=tot;i++){
                fail[i]=0; len[i]=0; cnt[i]=0;
                for(int j=0;j<num;j++) ch[i][j]=0;
            }
            last=tot=ans=0;
        }
    }pam;
    const int maxn=2e6+10;
    const int mod=19930726;
    #define ll long long
    char ss[maxn];
    int quick(int x,int n){
        int ans=1;
        while(n){
            if(n&1) ans=1ll*ans*x%mod;
            x=1ll*x*x%mod;
            n=n/2;
        }
        return ans;
    
    }
    int main(){
        ll n,k; scanf("%lld %lld",&n,&k);
        scanf("%s",ss);
        pam.inint();
        for(int i=0;i<n;i++)pam.add(ss[i],i);
        pam.count();
        ll ans=1;
        ll w=0;
        for(int i=n;i>=1;i--){
                //cout<<numm[i]<<endl;
            if(i%2==1) w+=numm[i];
            if(i%2==1 && k){
                if(numm[i]<=k){
                    ans=1ll*ans*quick(i,numm[i])%mod;
                    k-=numm[i];
                }
                else {
                    ans=1ll*ans*quick(i,k)%mod;
                    k=0;
                }
            }
        }
        if(w<k) printf("-1
    ");
        else printf("%lld
    ",ans);
    }
    View Code

     hdu 5157

    #include<bits/stdc++.h>
    using namespace std;
    struct PAM{
        #define ll long long
        #define LL long long
        static const int maxn=2e5+10;
        static const int num=27;
        char ss[maxn];  int c=0;
        int fail[maxn],cnt[maxn],len[maxn],ch[maxn][num];
        int last,tot;
        int sum[maxn];
        //LL ans;
        void inint(){
            c=0;
            last=0;  tot=0;
            fail[0]=fail[1]=1;
            len[0]=0; len[1]=-1; tot++;
        }
        int get_fail(int p,int pos){
             while(ss[pos-len[p]-1]!=ss[pos]) p=fail[p];
             return p;
        }
        void add(int x,int pos){
            ss[c]='a'+x;  c++;
            int p=get_fail(last,pos);
            if(!ch[p][x]){
                len[++tot]=len[p]+2;
                fail[tot]=ch[get_fail(fail[p],pos)][x];
                ch[p][x]=tot; //ans++;
            }
            cnt[last=ch[p][x]]++;
        }
        int dfs(int x){
            if(x==0 || x==1) return 0;
            if(sum[x]!=0) return sum[x];
            return sum[x]=dfs(fail[x])+1;
        }
        int work(){ return dfs(last); }
        void clear(){
            for(int i=0;i<=tot;i++){
                fail[i]=0; len[i]=0; cnt[i]=0; sum[i]=0;
                for(int j=0;j<num;j++) ch[i][j]=0;
            }
            last=tot=0;
        }
    }pam;
    #define ll long long
    const int maxn=1e5+10;
    char ss[maxn];
    ll a[maxn];
    ll b[maxn];
    ll sumb[maxn];
    int main(){
        while(scanf("%s",ss)!=EOF){
            int l=strlen(ss);
            pam.inint();
            for(int i=0;i<l;i++){
                pam.add(ss[i]-'a',i);
                a[i]=pam.work();
            }
            pam.clear();
            pam.inint();
            for(int i=l-1;i>=0;i--){
                pam.add(ss[i]-'a',l-1-i);
                b[i]=pam.work();
            }
            for(int i=l-1;i>=0;i--){
                sumb[i]=sumb[i+1]+b[i];
            }
            ll ans=0;
            for(int i=0;i<l;i++){
                ans+=1ll*a[i]*sumb[i+1];
            }
            printf("%lld
    ",ans);
            for(int i=0;i<=l;i++) a[i]=b[i]=sumb[i]=0;
            pam.clear();
        }
    }
    View Code

    hdu  6599  回文自动机   哈希  回文串 (l-r)回文  (l-(l+r)/2)回文)

    #include<bits/stdc++.h>
    #define ll long long
    #define LL long long
    using namespace std;
    const int maxn=3e5+10;
    const int mod=1e9+7;
    const int h1=222333;
    char ss[maxn];
    int a[maxn];
    int ha[maxn];
    int hb[maxn];
    int hh[maxn];
    struct PAM{
        #define ll long long
        #define LL long long
        static const int maxn=3e5+10;
        static const int num=27;
        int fail[maxn],cnt[maxn],len[maxn],ch[maxn][num];
        int last,tot;
        LL ans;
        void inint(){
            last=0;  tot=0;
            fail[0]=fail[1]=1;
            len[0]=0; len[1]=-1; tot++;
        }
        int get_fail(int p,int pos){
             while(ss[pos-len[p]-1]!=ss[pos]) p=fail[p];
             return p;
        }
        void add(int x,int pos){
            int p=get_fail(last,pos);
            if(!ch[p][x]){
                len[++tot]=len[p]+2;
                fail[tot]=ch[get_fail(fail[p],pos)][x];
                ch[p][x]=tot; ans++;
            }
            cnt[last=ch[p][x]]++;
        }
        void count(){  //  bu zhi bu tong hui wen ge shu
            for(int i=tot;i>=0;i--){
                cnt[fail[i]]+=cnt[i];
            }
        }
        void dfs(int x,int pos){
            for(int i=0;i<num;i++){
                if(ch[x][i]){
                    if(pos==0) ha[pos]=(1ll*i)%mod;
                    else       ha[pos]=(1ll*ha[pos-1]*h1+i)%mod;
                    if(pos==0) hb[pos]=(1ll*i*hh[pos])%mod;
                    else       hb[pos]=(1ll*i*hh[pos]+hb[pos-1])%mod;
                    int k=ch[x][i];
                    if(ha[pos]==hb[pos]){
                        a[len[k]]+=cnt[k];
                    }
                    dfs(k,pos+1);
    
                }
            }
        }
        void work(){
            dfs(0,0);
            dfs(1,0);
        }
        void clear(){
            for(int i=0;i<=tot;i++){
                fail[i]=0; len[i]=0; cnt[i]=0;
                for(int j=0;j<num;j++) ch[i][j]=0;
            }
            last=tot=ans=0;
        }
    }pam;
    int main(){
        hh[0]=1;  for(int i=1;i<maxn;i++) hh[i]=1ll*hh[i-1]*h1%mod;
        while(~scanf("%s",ss)){
            int l=strlen(ss); pam.inint();  //cout<<l<<endl;
            for(int i=0;i<l;i++)  pam.add(ss[i]-'a',i);
            pam.count();  pam.work();
            for(int i=1;i<=l;i++){
                if(i!=1) printf(" ");
                printf("%d",a[i]); a[i]=0;
            }printf("
    ");
            pam.clear();
        }
    }
    View Code

    马拉车  最长回文

    #include<bits/stdc++.h>
    const int maxn=1e6+10;
    using namespace std;
    int p[maxn*2+10];
    string manacher(string ss)
    {
        string tt="$#";
        for(int i=0;i<ss.size();i++){tt+=ss[i]; tt+="#";}
        int mx=0;
        int id=0;
        int mid=0;
        int ls=0;
        for(int i=1;i<tt.size();i++)
        {
            if(mx>i) p[i]=min(p[2*id-i],mx-i);
            else     p[i]=1;
            while(tt[i+p[i]]==tt[i-p[i]]) p[i]++;
            if(i+p[i]>mx)
            {
                mx=i+p[i];
                id=i;
            }
            if(ls<p[i])
            {
                ls=p[i]; mid=i;
            }
        }
        for(int i=1;i<tt.size();i++) p[i]=0;
        return ss.substr((mid - ls) / 2, ls - 1);
    }
    char a[maxn];
    int main()
    {
        while(scanf("%s",&a)!=EOF)
        {
            string ss="";
            int l=strlen(a);
            for(int i=0;i<l;i++) ss+=a[i];
            ss=manacher(ss);
            cout<<ss.size()<<endl;
        }
    }
    View Code

    后缀自动机

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    struct SAM{
        #define ll long long 
        #define LL long long 
        static const int maxn=1e5+10;  
        static const int MAXN=maxn;  //大小为字符串长度两倍
        static const int LS=26;
        int tot,last,ch[MAXN][LS],fa[MAXN],len[MAXN];
        int num[MAXN];
        void init(){
            last=tot=1;  len[1] = 0;
            memset(ch[1],0,sizeof ch[1]);
        }
        void add( int x) {
            int p = last, np = last = ++tot;  num[tot]=1;
            len[np] = len[p] + 1;//cnt[last] = 1;
            memset( ch[np], 0, sizeof ch[np]);
            while( p && !ch[p][x]) ch[p][x] = np, p = fa[p];
            if( p == 0)  fa[np] = 1;
            else{
                int q = ch[p][x];
                if( len[q] == len[p] + 1)  fa[np] = q;
                else{
                    int nq = ++tot;
                    memcpy( ch[nq], ch[q], sizeof ch[q]);
                    len[nq] = len[p] + 1, fa[nq] = fa[q], fa[q] = fa[np] = nq;
                    while( p && ch[p][x] == q)  ch[p][x] = nq, p = fa[p];
                }
            }
        }
        void use(){
            ll ans=0;
            for(int i=2;i<=tot;i++) { ans+=len[i]-len[fa[i]]; }
            printf("%lld
    ",ans);
        }
    }sam;
    const int maxn=1e6+10;
    char ss[maxn];
    int main(){
        int T; scanf("%d",&T);
        while(T--){
            scanf("%s",ss); int l=strlen(ss); sam.init();
            for(int i=0;i<l;i++)  sam.add(ss[i]-'a');
            sam.use();
        }
    }
    View Code
    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    struct SAM    // /* https://www.cnblogs.com/weeping/p/7516063.html */
    {
        static const int MAXN = 50000<<1;//大小为字符串长度两倍
        static const int LetterSize = 300;
        int tot, last, ch[MAXN][LetterSize], fa[MAXN], len[MAXN];
        int num[MAXN];
        void init( void)
        {
            last = tot = 1;  len[1] = 0;
            memset( ch[1], 0, sizeof ch[1]);
        }
        void add( int x) {
            int p = last, np = last = ++tot;  num[tot]=1;
            len[np] = len[p] + 1;//cnt[last] = 1;
            memset( ch[np], 0, sizeof ch[np]);
            while( p && !ch[p][x]) ch[p][x] = np, p = fa[p];
            if( p == 0)  fa[np] = 1;
            else
            {
                int q = ch[p][x];
                if( len[q] == len[p] + 1)  fa[np] = q;
                else
                {
                    int nq = ++tot;
                    memcpy( ch[nq], ch[q], sizeof ch[q]);
                    len[nq] = len[p] + 1, fa[nq] = fa[q], fa[q] = fa[np] = nq;
                    while( p && ch[p][x] == q)  ch[p][x] = nq, p = fa[p];
                }
            }
        }
        void use(){
            ll ans=0;
            for(int i=2;i<=tot;i++) { ans+=len[i]-len[fa[i]]; }
            printf("%lld
    ",ans);
        }
    }sam;
    const int maxn=1e6+10;
    char ss[maxn];
    int main(){
        int T; scanf("%d",&T);
        while(T--){
            scanf("%s",ss); int l=strlen(ss); sam.init();
            for(int i=0;i<l;i++)  sam.add(ss[i]-'a');
            sam.use();
        }
    }
    View Code

    给定一个只包含小写字母的字符串S,  请你求出 S 的所有出现次数不为1的子串的出现次数乘上该子串长度的最大值  (次数一样 取最大长度)   (后缀自动机拓扑排序模板)

    // luogu-judger-enable-o2
    
    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    struct SAM    // /* https://www.cnblogs.com/weeping/p/7516063.html */
    {
        static const int MAXN = 1000000<<1;//大小为字符串长度两倍
        static const int LetterSize = 26;
        int tot, last, ch[MAXN][LetterSize], fa[MAXN], len[MAXN];
        int num[MAXN];
        //int sum[MAXN], tp[MAXN], cnt[MAXN]; //sum,tp用于拓扑排序,tp为排序后的数组
        void init( void)
        {
            last = tot = 1;  len[1] = 0;
            memset( ch[1], 0, sizeof ch[1]);
        }
        void add( int x) {
            int p = last, np = last = ++tot;  num[tot]=1;
            len[np] = len[p] + 1;//cnt[last] = 1;
            memset( ch[np], 0, sizeof ch[np]);
            while( p && !ch[p][x]) ch[p][x] = np, p = fa[p];
            if( p == 0)  fa[np] = 1;
            else
            {
                int q = ch[p][x];
                if( len[q] == len[p] + 1)  fa[np] = q;
                else
                {
                    int nq = ++tot;
                    memcpy( ch[nq], ch[q], sizeof ch[q]);
                    len[nq] = len[p] + 1, fa[nq] = fa[q], fa[q] = fa[np] = nq;
                    while( p && ch[p][x] == q)  ch[p][x] = nq, p = fa[p];
                }
            }
        }
        /*void toposort( void){
            for(int i = 1; i <= len[last]; i++)   sum[i] = 0;
            for(int i = 1; i <= tot; i++)   sum[len[i]]++;
            for(int i = 1; i <= len[last]; i++)   sum[i] += sum[i-1];
            for(int i = 1; i <= tot; i++)   tp[sum[len[i]]--] = i;
            for(int i = tot; i; i--)   cnt[fa[tp[i]]] += cnt[tp[i]];
        }*/
        vector<int> vs[MAXN];
        ll ans=0;
        void build(){
            for(int i=2;i<=tot;i++)  { vs[fa[i]].push_back(i);   }
            //for(int i=1;i<=tot;i++)  num[i]=1;
        }
        void dfs(int u){
            for(int i=0;i<vs[u].size();i++){
                dfs(vs[u][i]);
                num[u]+=num[vs[u][i]];
            }
            if(num[u]!=1) ans=max(ans,1ll*num[u]*len[u]);
            //cout<<u<<"   "<<ans<<endl;
        }
    } sam;
    const int maxn=1e6+10;
    char ss[maxn];
    int main(){
        scanf("%s",ss); int l=strlen(ss); sam.init();
        for(int i=0;i<l;i++) sam.add(ss[i]-'a');
        sam.build();
        sam.dfs(1);
        printf("%lld
    ",sam.ans);
    }
    View Code

    本质不同字符串个数(模板题)New Distinct Substrings SPOJ - SUBST1 

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    struct SAM{
        static const int MAXN = 50000<<1;//大小为字符串长度两倍
        static const int LetterSize = 300;
        int tot, last, ch[MAXN][LetterSize], fa[MAXN], len[MAXN];
        int num[MAXN];
        void init( void)
        {
            last = tot = 1;  len[1] = 0;
            memset( ch[1], 0, sizeof ch[1]);
        }
        void add( int x) {
            int p = last, np = last = ++tot;  num[tot]=1;
            len[np] = len[p] + 1;//cnt[last] = 1;
            memset( ch[np], 0, sizeof ch[np]);
            while( p && !ch[p][x]) ch[p][x] = np, p = fa[p];
            if( p == 0)  fa[np] = 1;
            else
            {
                int q = ch[p][x];
                if( len[q] == len[p] + 1)  fa[np] = q;
                else
                {
                    int nq = ++tot;
                    memcpy( ch[nq], ch[q], sizeof ch[q]);
                    len[nq] = len[p] + 1, fa[nq] = fa[q], fa[q] = fa[np] = nq;
                    while( p && ch[p][x] == q)  ch[p][x] = nq, p = fa[p];
                }
            }
        }
        void use(){
            ll ans=0;
            for(int i=2;i<=tot;i++) { ans+=len[i]-len[fa[i]]; }
            printf("%lld
    ",ans);
        }
    }sam;
    const int maxn=1e6+10;
    char ss[maxn];
    int main(){
        int T; scanf("%d",&T);
        while(T--){
            scanf("%s",ss); int l=strlen(ss); sam.init();
            for(int i=0;i<l;i++)  sam.add(ss[i]-'a');
            sam.use();
        }
    }
    View Code

    hdu 4622  本质不同字符串个数  后缀自动机的清空   

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    struct SAM
    {
        static const int MAXN = 50000<<1;//大小为字符串长度两倍
        static const int LetterSize = 27;
        int tot, last, ch[MAXN][LetterSize], fa[MAXN], len[MAXN];
        int num[MAXN];
        void init( void){
            last = tot = 1;  len[1] = 0;
            memset( ch[1], 0, sizeof ch[1]);
        }
        void add( int x) {
            int p = last, np = last = ++tot;  num[tot]=1;
            len[np] = len[p] + 1;//cnt[last] = 1;
            memset( ch[np], 0, sizeof ch[np]);
            while( p && !ch[p][x]) ch[p][x] = np, p = fa[p];
            if( p == 0)  fa[np] = 1;
            else
            {
                int q = ch[p][x];
                if( len[q] == len[p] + 1)  fa[np] = q;
                else
                {
                    int nq = ++tot;
                    memcpy( ch[nq], ch[q], sizeof ch[q]);
                    len[nq] = len[p] + 1, fa[nq] = fa[q], fa[q] = fa[np] = nq;
                    while( p && ch[p][x] == q)  ch[p][x] = nq, p = fa[p];
                }
            }
        }
        void use(){
            ll ans=0;
            for(int i=2;i<=tot;i++) { ans+=len[i]-len[fa[i]]; }
            printf("%lld
    ",ans);
        }
    }sam;
    const int maxn=1e6+10;
    char ss[maxn];
    int dp[2005][2005];
    int main(){
        int T; scanf("%d",&T);
        while(T--){
            scanf("%s",ss);
            int q; scanf("%d",&q);
            while(q--){
               sam.init();
               int l,r; scanf("%d %d",&l,&r);
               for(int i=l;i<=r;i++) sam.add(ss[i-1]-'a');
               sam.use();
            }
        }
        return 0;
    }
    View Code

     两字符串的最长相同字串

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    struct SAM{
        static const int MAXN = 250010<<1;//大小为字符串长度两倍
        static const int LetterSize = 300;
        int tot, last, ch[MAXN][LetterSize], fa[MAXN], len[MAXN];
        int num[MAXN];
        void init( void){
            last = tot = 1;  len[1] = 0; len[0]=0;
            memset( ch[1], 0, sizeof ch[1]);
        }
        void add( int x) {
            int p = last, np = last = ++tot;  num[tot]=1;
            len[np] = len[p] + 1;
            memset(ch[np],0,sizeof ch[np]);
            while(p&&!ch[p][x]) ch[p][x] = np, p = fa[p];
            if( p == 0)  fa[np] = 1;
            else{
                int q = ch[p][x];
                if( len[q] == len[p] + 1)  fa[np] = q;
                else{
                    int nq = ++tot;
                    memcpy( ch[nq], ch[q], sizeof ch[q]);
                    len[nq] = len[p] + 1, fa[nq] = fa[q], fa[q] = fa[np] = nq;
                    while( p && ch[p][x] == q)  ch[p][x] = nq, p = fa[p];
                }
            }
        }
    }sam;
    const int maxn=1e6+10;
    char ss[maxn];
    char tt[maxn];
    int main(){
        scanf("%s",ss); int l=strlen(ss); sam.init();
        for(int i=0;i<l;i++)  sam.add(ss[i]-'a');
        scanf("%s",tt); int r=strlen(tt);
        int ans=0;
        int p=1;
        int d=0;
        for(int i=0;i<r;i++){
           if(sam.ch[p][tt[i]-'a']){
                p=sam.ch[p][tt[i]-'a'];
                d++;
           }
           else {
                while(sam.ch[p][tt[i]-'a']==0 && p!=1){
                    p=sam.fa[p];
                    d=sam.len[p];
                }
                if(sam.ch[p][tt[i]-'a'])  { p=sam.ch[p][tt[i]-'a']; d++;}
           }
           //cout<<d<<endl;
           ans=max(ans,d);
        }
        printf("%d
    ",ans);
    }
    View Code

     hdu 6583   后缀自动机 + dp    http://acm.hdu.edu.cn/showproblem.php?pid=6583

    #pragma GCC optimize(2)
    #pragma GCC optimize(3)
    #pragma GCC optimize(4)
    #include<bits/stdc++.h>
    #define ll long long
    #define LL long long
    using namespace std;
    struct SAM
    {
        static const int MAXN = 200010<<1;//大小为字符串长度两倍
        static const int LetterSize = 26;
        int tot, last, ch[MAXN][LetterSize], fa[MAXN], len[MAXN];
        int num[MAXN];
        void init( void)
        {
            last = tot = 1;  len[1] = 0; fa[1]=0;
            memset( ch, 0, sizeof(ch));
            memset( fa,0,sizeof(fa));
            memset( len,0,sizeof(len));
        }
        void add( int x) {
            int p = last, np = last = ++tot;  num[tot]=1;
            len[np] = len[p] + 1;
            memset( ch[np], 0, sizeof ch[np]);
            while( p && !ch[p][x]) ch[p][x] = np, p = fa[p];
            if( p == 0)  fa[np] = 1;
            else
            {
                int q = ch[p][x];
                if( len[q] == len[p] + 1)  fa[np] = q;
                else
                {
                    int nq = ++tot;
                    memcpy( ch[nq], ch[q], sizeof ch[q]);
                    len[nq] = len[p] + 1, fa[nq] = fa[q], fa[q] = fa[np] = nq;
                    while( p && ch[p][x] == q)  ch[p][x] = nq, p = fa[p];
                }
            }
        }
    }sam;
    const int maxn=2e5+10;
    char ss[maxn];
    ll dp[maxn];
    int main(){
        while(~scanf("%s",ss)){
            int p,q; scanf("%d %d",&p,&q);
            int l=strlen(ss);
            sam.init();
            int now=1;
            int j=0;
            for(int i=0;i<l;i++) dp[i]=1e18;
            for(int i=0;i<l;i++){
                if(i==0)   dp[i]=p;
                else       dp[i]=min(dp[i],dp[i-1]+p);
                int x=ss[i]-'a';
                while(  (!sam.ch[now][x] || i-j+1>=j+1) &&j<=i    ){
                      sam.add(ss[j++]-'a');
                      while(now && sam.len[sam.fa[now]]>=i-j) now=sam.fa[now];
                      if(!now) now=1;
                }
                now=sam.ch[now][x];
                while(now && sam.len[sam.fa[now]]>=i-j+1) now=sam.fa[now];
                if(!now) now=1;
                if(i>=j){
                    dp[i]=min(dp[i],dp[j-1]+q);
                }
               // cout<<dp[i]<<"  "<<i<<"   "<<j<<endl;
            }
            printf("%lld
    ",dp[l-1]);
        }
    }
    View Code

     vjudge C - Lexicographical Substring Search SPOJ - SUBLEX    拓扑排序   子串第K大 (不包含重复的)    注意 1-tot 不是拓扑序列

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    struct SAM{
        #define ll long long
        #define LL long long
        static const int maxn=1000010<<1;//大小为字符串长度两倍
        static const int LS=27;
        int tot, last, ch[maxn][LS], fa[maxn], len[maxn];
        int num[maxn];
        void init( void){
            last = tot = 1;  len[1] = 0; len[0]=0;
            memset( ch[1], 0, sizeof ch[1]);
        }
        void add( int x) {
            int p = last, np = last = ++tot;  num[tot]=1;
            len[np] = len[p] + 1;
            memset(ch[np],0,sizeof ch[np]);
            while(p&&!ch[p][x]) ch[p][x] = np, p = fa[p];
            if( p == 0)  fa[np] = 1;
            else{
                int q = ch[p][x];
                if( len[q] == len[p] + 1)  fa[np] = q;
                else{
                    int nq = ++tot;
                    memcpy( ch[nq], ch[q], sizeof ch[q]);
                    len[nq] = len[p] + 1, fa[nq] = fa[q], fa[q] = fa[np] = nq;
                    while( p && ch[p][x] == q)  ch[p][x] = nq, p = fa[p];
                }
            }
        }
        //  1-tot  不是拓扑序列   
        vector<pair<int,int> > vs[maxn];
        ll dp[maxn];
        int duu[maxn];
        void work(){
            for(int i=1;i<=tot;i++){
                for(int j=0;j<LS;j++){
                    if(ch[i][j]){
                        vs[i].push_back({ch[i][j],j});
                        duu[ch[i][j]]++;
                    }
                }
            }
            queue<pair<int,int> > qu;
            vector<int> vq;
            qu.push({1,0});
            while(!qu.empty()){
                int p=qu.front().first;  qu.pop();  vq.push_back(p);
                for(int j=0;j<vs[p].size();j++){
                    int u=vs[p][j].first;
                    duu[u]--; if(duu[u]==0){ qu.push(vs[p][j]); }
                }
            }
            for(int i=vq.size()-1;i>=0;i--){
                int w=vq[i];
                dp[w]=1;
                for(int j=0;j<LS;j++){
                    if(ch[w][j]){
                        int x=ch[w][j];
                        dp[w]+=dp[x];
                    }
                }
            }
        }
        void find(int p,ll k){
            for(int i=0;i<LS;i++){
                if(ch[p][i]){
                    int x=ch[p][i];
                    if(k<=dp[x]){
                        printf("%c",i+'a');
                        k--;
                        if(k){ find(x,k); }
                        return ;
                    }
                    else {
                        k-=dp[x];
                    }
                }
            }
        }
    }sam;
    const int maxn=1e6+10;
    char ss[maxn];
    char tt[maxn];
    int main(){
        scanf("%s",ss); int l=strlen(ss); sam.init();
        for(int i=0;i<l;i++)  sam.add(ss[i]-'a');
        sam.work();
        int q; scanf("%d",&q);
        while(q--){ int k; scanf("%d",&k); sam.find(1,k);printf("
    "); }
    }
    View Code

    vjudge  B - Substrings SPOJ - NSUBSTR     本质字符串个数 (直接跑后缀树)   利用后缀树的性质优化区间修改 单点最大值

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    int a[1000006];
    struct SAM{
        static const int MAXN = 250010<<1;//大小为字符串长度两倍
        static const int LS = 27;
        int tot, last, ch[MAXN][LS], fa[MAXN], len[MAXN];
        int num[MAXN];
        void init( void){
            last = tot = 1;  len[1] = 0;
            memset( ch[1], 0, sizeof ch[1]);
        }
        void add( int x) {
            int p = last, np = last = ++tot;  num[tot]=1;
            len[np] = len[p] + 1;//cnt[last] = 1;
            memset( ch[np], 0, sizeof ch[np]);
            while( p && !ch[p][x]) ch[p][x] = np, p = fa[p];
            if( p == 0)  fa[np] = 1;
            else
            {
                int q = ch[p][x];
                if( len[q] == len[p] + 1)  fa[np] = q;
                else
                {
                    int nq = ++tot;
                    memcpy( ch[nq], ch[q], sizeof ch[q]);
                    len[nq] = len[p] + 1, fa[nq] = fa[q], fa[q] = fa[np] = nq;
                    while( p && ch[p][x] == q)  ch[p][x] = nq, p = fa[p];
                }
            }
        }
    
        vector<int> vs[MAXN];
        void dfs2(int u){
            for(int i=0;i<vs[u].size();i++){
                dfs2(vs[u][i]);
                num[u]+=num[vs[u][i]];
            }
        }
        void build(){
            for(int i=2;i<=tot;i++)  { vs[fa[i]].push_back(i);   }
        }
        void work(){
            build();
            dfs2(1);
            for(int i=1;i<=tot;i++){
                a[len[i]]=max(a[len[i]],num[i]);
            }
        }
    }sam;
    const int maxn=1e6+10;
    char ss[maxn];
    int main(){
    
        scanf("%s",ss); int l=strlen(ss);
        sam.init();
        for(int i=0;i<l;i++)  sam.add(ss[i]-'a');
        sam.work();
        for(int i=l;i>=1;i--){
            a[i]=max(a[i+1],a[i]);
        }
        for(int i=1;i<=l;i++){
            printf("%d
    ",a[i]);
        }
        return 0;
    }
    View Code

     多个字符串的最长公共子串长度  拓扑排序    后缀树上父子关系

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    struct SAM   {
        static const int  maxn=1000010<<1;//大小为字符串长度两倍
        static const int  LS=27;
        int tot, last, ch[maxn][LS], fa[maxn], len[maxn];
        int sum[maxn], tp[maxn];
        int num[maxn];
        int dp[maxn];
        void init( void){
            last = tot = 1;  len[1] = 0;
            memset( ch[1], 0, sizeof ch[1]);
        }
        void add( int x) {
            int p = last, np = last = ++tot;
            len[np] = len[p] + 1;
            memset( ch[np], 0, sizeof ch[np]);
            while( p && !ch[p][x]) ch[p][x] = np, p = fa[p];
            if( p == 0)  fa[np] = 1;
            else{
                int q = ch[p][x];
                if( len[q] == len[p] + 1)  fa[np] = q;
                else{
                    int nq = ++tot;
                    memcpy( ch[nq], ch[q], sizeof ch[q]);
                    len[nq] = len[p] + 1, fa[nq] = fa[q], fa[q] = fa[np] = nq;
                    while( p && ch[p][x] == q)  ch[p][x] = nq, p = fa[p];
                }
            }
        }
        void toposort( void){
            for(int i = 1; i <= len[last]; i++)   sum[i] = 0;
            for(int i = 1; i <= tot; i++)   sum[len[i]]++;
            for(int i = 1; i <= len[last]; i++)   sum[i] += sum[i-1];
            for(int i = 1; i <= tot; i++)   tp[sum[len[i]]--] = i;
    
        }
        void make(){
            for(int i=1;i<=tot;i++) num[i]=len[i];
            toposort();
        }
        void  use(char *tt){
            int l=strlen(tt);
            int p=1;
            int lll=0;
            for(int i=0;i<l;i++){
                   if(ch[p][tt[i]-'a']){
                        p=ch[p][tt[i]-'a']; lll++;
                   }
                   else {
                        while(ch[p][tt[i]-'a']==0 && p) p=fa[p];
                        if(!p) { lll=0; p=1; }
                        else   { lll=len[p]+1; p=ch[p][tt[i]-'a']; }
                   }
                   dp[p]=max(dp[p],lll);
            }
            for(int i=tot;i>=1;i--){
                int p=tp[i];
                if(num[p]>dp[p]) num[p]=dp[p];
                if(fa[p] && dp[fa[p]]<dp[p]) dp[fa[p]]=dp[p];
                dp[p]=0;
            }
    
        }
        void work(){
            int ans=0;
            for(int i=1;i<=tot;i++){
                ans=max(ans,num[i]);
            }
            printf("%d
    ",ans);
        }
    }sam;
    const int maxn=1e6+10;
    char ss[maxn];
    char tt[maxn];
    int main(){
        scanf("%s",ss); int l=strlen(ss); sam.init();
        for(int i=0;i<l;i++)  sam.add(ss[i]-'a');
        sam.make();
        int c=0; while(++c<=100 && scanf("%s",tt)!=EOF ){ sam.use(tt);  }
        sam.work();
    }
    View Code

     hdu 4436  字串和

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    struct SAM{
        #define ll long long
        #define LL long long
        static const int maxn=1e6+10;
        static const int MAXN=maxn;  //大小为字符串长度两倍
        static const int LS=11;
        static const int mod=2012;
        int tot,last,ch[MAXN][LS],fa[MAXN],len[MAXN];
        int sum[MAXN],tp[MAXN],cnt[MAXN]; // sum tp 用于拓扑排序  cnt 用于计数
        int vis[maxn];
        void init(){
            last=tot=1;  len[1] = 0;
            memset(ch[1],0,sizeof ch[1]);
        }
        void add( int x) {
           // cout<<x<<endl;
            int p = last, np = last = ++tot;
            len[np] = len[p] + 1;   //cnt[last] = 1;  统计每种字符串的个数
            vis[np]=(x==10);
            memset( ch[np], 0, sizeof ch[np]);
            while( p && !ch[p][x]) ch[p][x] = np, p = fa[p];
            if( p == 0)  fa[np] = 1;
            else{
                int q = ch[p][x];
                if( len[q] == len[p] + 1)  fa[np] = q;
                else{
                    int nq = ++tot;
                    memcpy( ch[nq], ch[q], sizeof ch[q]);
                    len[nq] = len[p] + 1, fa[nq] = fa[q], fa[q] = fa[np] = nq;
                    vis[nq]=vis[q];
                    while( p && ch[p][x] == q)  ch[p][x] = nq, p = fa[p];
                }
            }
        }
        void toposort(){
            for(int i = 1; i <= len[last]; i++)   sum[i] = 0;
            for(int i = 1; i <= tot; i++)   sum[len[i]]++;
            for(int i = 1; i <= len[last]; i++)   sum[i] += sum[i-1];
            for(int i = 1; i <= tot; i++)   tp[sum[len[i]]--] = i;
            // for(int i = tot; i; i--)   cnt[fa[tp[i]]] += cnt[tp[i]];
        }
        int dp[maxn];
        //int cnt[maxn];
        void make(){
            toposort();
            int ans=0;
            cnt[1]=1;
            for(int i=1;i<=tot;i++){
                int x=tp[i];
                ans+=dp[x]%mod; ans%=mod;
                for(int j=0;j<LS-1;j++){
                    if(j==0 && i==1 ) continue;
                    if(ch[x][j] && vis[x]==0 ){
                        int y=ch[x][j];
                        cnt[y]+=cnt[x];
                        cnt[y]%=mod;
                        dp[y]+=dp[x]*10+j*cnt[x];
                        dp[y]%=mod;
    
                    }
                }
                dp[x]=0;
                cnt[x]=0;
            }
            printf("%d
    ",ans%mod);
        }
    }sam;
    const int maxn=1e6+10;
    char ss[maxn];
    int main(){
        int n;
        while(scanf("%d",&n)!=EOF){
            sam.init();
            for(int i=1;i<=n;i++){
                scanf("%s",ss);
                int l=strlen(ss);
                for(int j=0;j<l;j++) sam.add(ss[j]-'0');
                if(i!=n) sam.add(10);
            }
            sam.make();
        }
    }
    View Code

     poj 3415  两字符串的相同字串  且长度大于K 的对数

    #include<stdio.h>
    #include<iostream>
    #include<algorithm>
    #include<string.h>
    #include<string>
    using namespace std;
    struct SAM{
        #define ll long long
        #define LL long long
        static const int  maxn=1000010<<1;//大小为字符串长度两倍
        static const int  MAXN=maxn;
        static const int  LS=54;
        int tot, last, ch[maxn][LS], fa[maxn], len[maxn];
        int sum[MAXN], tp[MAXN], cnt[MAXN];
        void init( void){
            last = tot = 1;  len[1] = 0;
            memset( ch[1], 0, sizeof ch[1]);
        }
        void add( int x) {
            int p = last, np = last = ++tot;    cnt[last]=1;
            len[np] = len[p] + 1;
            memset( ch[np], 0, sizeof ch[np]);
            while( p && !ch[p][x]) ch[p][x] = np, p = fa[p];
            if( p == 0)  fa[np] = 1;
            else{
                int q = ch[p][x];
                if( len[q] == len[p] + 1)  fa[np] = q;
                else
                {
                    int nq = ++tot;
                    memcpy( ch[nq], ch[q], sizeof ch[q]);
                    len[nq] = len[p] + 1, fa[nq] = fa[q], fa[q] = fa[np] = nq;
                    while( p && ch[p][x] == q)  ch[p][x] = nq, p = fa[p];
                }
            }
        }
        void toposort( void){
            for(int i = 1; i <= len[last]; i++)   sum[i] = 0;
            for(int i = 1; i <= tot; i++)   sum[len[i]]++;
            for(int i = 1; i <= len[last]; i++)   sum[i] += sum[i-1];
            for(int i = 1; i <= tot; i++)   tp[sum[len[i]]--] = i;
            for(int i = tot; i; i--)        cnt[fa[tp[i]]] += cnt[tp[i]];
        }
        ll ppp[maxn];
        void s_init(int k){
            for(int i=1;i<=tot;i++){
                int x=tp[i];
                if(len[x]>=k){  ppp[x]=min(len[x]-len[fa[x]],len[x]-k+1)*cnt[x];  }
                ppp[x]+=ppp[fa[x]];
            }
        }
        void slove(char *tt,int k){
            toposort();  s_init(k);
            int p=1,d=0;  ll ans=0;
            int l=strlen(tt);
            for(int i=0;i<l;i++){
                int x=0;
               if(tt[i]>='A' && tt[i]<='Z' ) x=tt[i]-'A'+26;
               else x=tt[i]-'a';
               if(~ch[p][x]){
                     while(ch[p][x]==0 && p!=1){ p=fa[p];  d=len[p]; }
               }
               if(ch[p][x]){
                    p=ch[p][x]; d++;
                    if(d>=k) {
                        ans+=cnt[p]*(d-max(len[fa[p]],k-1));
                        ans+=ppp[fa[p]];
                    }
               }
               else { p=1; d=0; }
            }
            printf("%lld
    ",ans);
        }
        void clear(){
            for(int i=1;i<=tot;i++){
                cnt[i]=0; tp[i]=0; ppp[i]=0;
            }
        }
    }sam;
    const int maxn=1e5+10;
    char ss[maxn];
    char tt[maxn];
    int main(){
        while(1){
            int k; scanf("%d",&k);if(k==0) break;
            scanf("%s",ss); int l=strlen(ss);
            sam.init();
            for(int i=0;i<l;i++){ if(ss[i]>='A' && ss[i]<='Z') sam.add(ss[i]-'A'+26); else sam.add(ss[i]-'a'); }
            scanf("%s",tt);sam.slove(tt,k);
            sam.clear();
        }
        return 0;
    }
    View Code

    后缀数组   模板

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define rank rk
    using namespace std;
    
    typedef long long LL;
    const int maxn = 1050005, M = 300;
    // sa[1-n] -> 0->n-1;
    int sa[maxn], rank[maxn], height[maxn];
    int wa[maxn], wb[maxn], wv[maxn], cnt[maxn];
    void SA(int *r, int n, int m) {
        int *x = wa, *y = wb;
        for(int i = 0; i < m; i++) cnt[i] = 0;
        for(int i = 0; i < n; i++) cnt[x[i] = r[i]]++;
        for(int i = 1; i < m; i++) cnt[i] += cnt[i - 1];
        for(int i = n - 1; i >= 0; i--) sa[--cnt[x[i]]] = i;
        for(int j = 1; j < n; j <<= 1) {
            int p = 0;
            for(int i = n - j; i < n; i++) y[p++] = i;
            for(int i = 0; i < n; i++) if(sa[i] >= j) y[p++] = sa[i] - j;
            for(int i = 0; i < n; i++) wv[i] = x[y[i]];
            for(int i = 0; i < m; i++) cnt[i] = 0;
            for(int i = 0; i < n; i++) cnt[wv[i]]++;
            for(int i = 1; i < m; i++) cnt[i] += cnt[i - 1];
            for(int i = n - 1; i >= 0; i--) sa[--cnt[wv[i]]] = y[i];
            swap(x, y);
            p = 1; x[sa[0]] = 0;
            for(int i = 1; i < n; i++)
                x[sa[i]] = y[sa[i - 1]] == y[sa[i]] && y[sa[i - 1] + j] == y[sa[i] + j] ? p - 1 : p++;
            if(p >= n) break;
            m = p;
        }
    }
    void calcHeight(int *r, int n) {
        int i, j, k;
        for(i = j = k = 0; i < n; height[rank[i++]] = k)
            for(k ? k-- : 0, j = sa[rank[i] - 1]; r[i + k] == r[j + k]; k++);
    }
    int n, s[maxn];
    char str[maxn];
    int main() {
        //int T; scanf("%d", &T);
        //while(T--) {
            scanf("%s", str); n = strlen(str);
            for(int i = 0; i < n; i++) s[i] = str[i]; s[n] = 0;
            SA(s, n + 1, M);
            for(int i = 0; i <= n; i++) rank[sa[i]] = i;
            calcHeight(s, n);
            int ans = (LL)n * (n + 1) >> 1;
            for(int i = 1; i <= n; i++) ans -= height[i];
            //printf("%d
    ", ans);
            for(int i=1;i<=n;i++){
                if(i!=1) cout<<" ";
                cout<<sa[i];
            }cout<<endl;
            for(int i=0;i<n;i++){
                if(i!=0) cout<<" ";
                cout<<rank[i];
            }cout<<endl;
        //}
        return 0;
    }
    View Code
    /*
        之前一直用倍增法,发现有些题目卡倍增法,而DC3却能AC,所以顺便弄了
        DC3的模版,看以后会不会用到,嗯,就是酱紫
        提一些注意点:1.MAXN开n的十倍大小;
                      2.dc3(r,sa,n+1,Max+1);r为待后缀处理的数组,sa为存储排名位置的数组,n+1和Max+1 都和倍增一样
                      3.calheight(r,sa,n);和倍增一样
        模版测试题目是 SPOJ 694 / SPOJ DISUBSTR Distinct Substrings【后缀数组】不相同的子串的个数
        做法和我之前写的那篇题解一样,大概就这些..
    */
    #include<cstdio>
    #include<algorithm>
    #include<queue>
    #include<iostream>
    #include<cmath>
    #include<cstring>
    #define ll long long
    #define rank ra
    using namespace std;
    #define F(x) ((x)/3+((x)%3==1?0:tb))
    #define G(x) ((x)<tb?(x)*3+1:((x)-tb)*3+2)
    const int MAXN = 500000+100;//n*10
    int sa[MAXN];
    int rank[MAXN];
    int height[MAXN];
    int n;
    char s[MAXN];
    int r[MAXN];
    int wa[MAXN],wb[MAXN],wv[MAXN];
    int wws[MAXN];
    void sort(int *r,int *a,int *b,int n,int m)
    {
          int i;
          for(i=0;i<n;i++) wv[i]=r[a[i]];
          for(i=0;i<m;i++) wws[i]=0;
          for(i=0;i<n;i++) wws[wv[i]]++;
          for(i=1;i<m;i++) wws[i]+=wws[i-1];
          for(i=n-1;i>=0;i--) b[--wws[wv[i]]]=a[i];
         return;
    }
    int c0(int *r,int a,int b)
    {return r[a]==r[b]&&r[a+1]==r[b+1]&&r[a+2]==r[b+2];}
    int c12(int k,int *r,int a,int b)
    {if(k==2) return r[a]<r[b]||r[a]==r[b]&&c12(1,r,a+1,b+1);
    else return r[a]<r[b]||r[a]==r[b]&&wv[a+1]<wv[b+1];}
    
    void dc3(int *r,int *sa,int n,int m)
    {
        int i,j,*rn=r+n,*san=sa+n,ta=0,tb=(n+1)/3,tbc=0,p;
        r[n]=r[n+1]=0;
        for(i=0;i<n;i++) if(i%3!=0) wa[tbc++]=i;
        sort(r+2,wa,wb,tbc,m);
        sort(r+1,wb,wa,tbc,m);
        sort(r,wa,wb,tbc,m);
        for(p=1,rn[F(wb[0])]=0,i=1;i<tbc;i++)
              rn[F(wb[i])]=c0(r,wb[i-1],wb[i])?p-1:p++;
        if(p<tbc) dc3(rn,san,tbc,p);
              else for(i=0;i<tbc;i++) san[rn[i]]=i;
        for(i=0;i<tbc;i++) if(san[i]<tb) wb[ta++]=san[i]*3;
        if(n%3==1) wb[ta++]=n-1;
        sort(r,wb,wa,ta,m);
        for(i=0;i<tbc;i++) wv[wb[i]=G(san[i])]=i;
        for(i=0,j=0,p=0;i<ta && j<tbc;p++)
              sa[p]=c12(wb[j]%3,r,wa[i],wb[j])?wa[i++]:wb[j++];
        for(;i<ta;p++) sa[p]=wa[i++];
        for(;j<tbc;p++) sa[p]=wb[j++];
        return;
    }
    void calheight(int *r, int *sa, int n)
    {
        int i, j, k = 0;
        for (i = 1; i <= n; ++i) rank[sa[i]] = i;
        for (i = 0; i < n; height[rank[i++]] = k)
            for (k ? k-- : 0, j = sa[rank[i] - 1]; r[i + k] == r[j + k]; ++k);
        return;
    }
    int main()
    {
        int t;
        scanf("%d",&t);
        while(t--){
            scanf("%s",s);
            int Max=-1;
            n=strlen(s);
            for(int i=0;i<n;i++){  r[i]=s[i];  if(r[i]>Max)Max=r[i]; }
            r[n]=0;
            dc3(r,sa,n+1,Max+1);
            calheight(r,sa,n);
            ll sum=0;
            for(int i=2;i<=n;i++)sum+=height[i];
            printf("%lld
    ",1ll*(1+n)*n/2-sum);
        }
        return 0;
    }
    
    DC3版本
    DC3版

    最小表示法

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define rank rk
    using namespace std;
    
    typedef long long LL;
    
    const int maxn = 30505, M = 300;
    // sa[1-n] -> 0->n-1;
    int sa[maxn], rank[maxn], height[maxn];
    
    int wa[maxn], wb[maxn], wv[maxn], cnt[maxn];
    void SA(int *r, int n, int m) {
        int *x = wa, *y = wb;
        for(int i = 0; i < m; i++) cnt[i] = 0;
        for(int i = 0; i < n; i++) cnt[x[i] = r[i]]++;
        for(int i = 1; i < m; i++) cnt[i] += cnt[i - 1];
        for(int i = n - 1; i >= 0; i--) sa[--cnt[x[i]]] = i;
        for(int j = 1; j < n; j <<= 1) {
            int p = 0;
            for(int i = n - j; i < n; i++) y[p++] = i;
            for(int i = 0; i < n; i++) if(sa[i] >= j) y[p++] = sa[i] - j;
            for(int i = 0; i < n; i++) wv[i] = x[y[i]];
            for(int i = 0; i < m; i++) cnt[i] = 0;
            for(int i = 0; i < n; i++) cnt[wv[i]]++;
            for(int i = 1; i < m; i++) cnt[i] += cnt[i - 1];
            for(int i = n - 1; i >= 0; i--) sa[--cnt[wv[i]]] = y[i];
            swap(x, y);
            p = 1; x[sa[0]] = 0;
            for(int i = 1; i < n; i++)
                x[sa[i]] = y[sa[i - 1]] == y[sa[i]] && y[sa[i - 1] + j] == y[sa[i] + j] ? p - 1 : p++;
            if(p >= n) break;
            m = p;
        }
    }
    
    void calcHeight(int *r, int n) {
        int i, j, k;
        for(i = j = k = 0; i < n; height[rank[i++]] = k)
            for(k ? k-- : 0, j = sa[rank[i] - 1]; r[i + k] == r[j + k]; k++);
    }
    
    int n, s[maxn];
    char str[maxn];
    int main() {
        int T; scanf("%d", &T);
        while(T--) {
            scanf("%s", str); n = strlen(str);
            for(int i = 0; i < n; i++) s[i]  = str[i];
            for(int i = 0; i < n; i++) s[i+n]=str[i];
            n=n*2;
            s[n] = 0;
            SA(s, n + 1, M);
            for(int i = 0; i <= n; i++) rank[sa[i]] = i;
            calcHeight(s, n);
            int f=0;
            int ans=1000000;
            for(int i = 1; i <= n; i++) {
                int x=sa[i];
    
                if(f==1){
                    if(x<n/2 && height[i] == n-sa[i-1] ){
                        ans=min(ans,x+1);
                    }
                    else break;
                    continue;
                }
                if(x<n/2){
                    ans=x+1; f=1;
                }
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
    View Code

    不同字串个数

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define rank rk
    using namespace std;
    typedef long long LL;
    const int maxn = 50005, M = 300;
    int sa[maxn], rank[maxn], height[maxn];
    int wa[maxn], wb[maxn], wv[maxn], cnt[maxn];
    void SA(int *r, int n, int m) {
        int *x = wa, *y = wb;
        for(int i = 0; i < m; i++) cnt[i] = 0;
        for(int i = 0; i < n; i++) cnt[x[i] = r[i]]++;
        for(int i = 1; i < m; i++) cnt[i] += cnt[i - 1];
        for(int i = n - 1; i >= 0; i--) sa[--cnt[x[i]]] = i;
        for(int j = 1; j < n; j <<= 1) {
            int p = 0;
            for(int i = n - j; i < n; i++) y[p++] = i;
            for(int i = 0; i < n; i++) if(sa[i] >= j) y[p++] = sa[i] - j;
            for(int i = 0; i < n; i++) wv[i] = x[y[i]];
            for(int i = 0; i < m; i++) cnt[i] = 0;
            for(int i = 0; i < n; i++) cnt[wv[i]]++;
            for(int i = 1; i < m; i++) cnt[i] += cnt[i - 1];
            for(int i = n - 1; i >= 0; i--) sa[--cnt[wv[i]]] = y[i];
            swap(x, y);
            p = 1; x[sa[0]] = 0;
            for(int i = 1; i < n; i++)
                x[sa[i]] = y[sa[i - 1]] == y[sa[i]] && y[sa[i - 1] + j] == y[sa[i] + j] ? p - 1 : p++;
            if(p >= n) break;
            m = p;
        }
    }
    void calcHeight(int *r, int n) {
        int i, j, k;
        for(i = j = k = 0; i < n; height[rank[i++]] = k)
            for(k ? k-- : 0, j = sa[rank[i] - 1]; r[i + k] == r[j + k]; k++);
    }
    int n, s[maxn];
    char str[maxn];
    int main() {
        int T; scanf("%d", &T);
        while(T--) {
            scanf("%s", str); n = strlen(str);
            for(int i = 0; i < n; i++) s[i] = str[i]; s[n] = 0;
            SA(s, n + 1, M);
            for(int i = 0; i <= n; i++) rank[sa[i]] = i;
            calcHeight(s, n);
            int ans = (LL)n * (n + 1) >> 1;
            for(int i = 1; i <= n; i++) ans -= height[i];
            printf("%d
    ", ans);
        }
        return 0;
    }
    View Code
    /*
        之前一直用倍增法,发现有些题目卡倍增法,而DC3却能AC,所以顺便弄了
        DC3的模版,看以后会不会用到,嗯,就是酱紫
        提一些注意点:1.MAXN开n的十倍大小;
                      2.dc3(r,sa,n+1,Max+1);r为待后缀处理的数组,sa为存储排名位置的数组,n+1和Max+1 都和倍增一样
                      3.calheight(r,sa,n);和倍增一样
        模版测试题目是 SPOJ 694 / SPOJ DISUBSTR Distinct Substrings【后缀数组】不相同的子串的个数
        做法和我之前写的那篇题解一样,大概就这些..
    */
    #include<cstdio>
    #include<algorithm>
    #include<queue>
    #include<iostream>
    #include<cmath>
    #include<cstring>
    #define ll long long
    #define rank ra
    using namespace std;
    #define F(x) ((x)/3+((x)%3==1?0:tb))
    #define G(x) ((x)<tb?(x)*3+1:((x)-tb)*3+2)
    const int MAXN = 500000+100;//n*10
    int sa[MAXN];
    int rank[MAXN];
    int height[MAXN];
    int n;
    char s[MAXN];
    int r[MAXN];
    int wa[MAXN],wb[MAXN],wv[MAXN];
    int wws[MAXN];
    void sort(int *r,int *a,int *b,int n,int m)
    {
          int i;
          for(i=0;i<n;i++) wv[i]=r[a[i]];
          for(i=0;i<m;i++) wws[i]=0;
          for(i=0;i<n;i++) wws[wv[i]]++;
          for(i=1;i<m;i++) wws[i]+=wws[i-1];
          for(i=n-1;i>=0;i--) b[--wws[wv[i]]]=a[i];
         return;
    }
    int c0(int *r,int a,int b)
    {return r[a]==r[b]&&r[a+1]==r[b+1]&&r[a+2]==r[b+2];}
    int c12(int k,int *r,int a,int b)
    {if(k==2) return r[a]<r[b]||r[a]==r[b]&&c12(1,r,a+1,b+1);
    else return r[a]<r[b]||r[a]==r[b]&&wv[a+1]<wv[b+1];}
    
    void dc3(int *r,int *sa,int n,int m)
    {
        int i,j,*rn=r+n,*san=sa+n,ta=0,tb=(n+1)/3,tbc=0,p;
        r[n]=r[n+1]=0;
        for(i=0;i<n;i++) if(i%3!=0) wa[tbc++]=i;
        sort(r+2,wa,wb,tbc,m);
        sort(r+1,wb,wa,tbc,m);
        sort(r,wa,wb,tbc,m);
        for(p=1,rn[F(wb[0])]=0,i=1;i<tbc;i++)
              rn[F(wb[i])]=c0(r,wb[i-1],wb[i])?p-1:p++;
        if(p<tbc) dc3(rn,san,tbc,p);
              else for(i=0;i<tbc;i++) san[rn[i]]=i;
        for(i=0;i<tbc;i++) if(san[i]<tb) wb[ta++]=san[i]*3;
        if(n%3==1) wb[ta++]=n-1;
        sort(r,wb,wa,ta,m);
        for(i=0;i<tbc;i++) wv[wb[i]=G(san[i])]=i;
        for(i=0,j=0,p=0;i<ta && j<tbc;p++)
              sa[p]=c12(wb[j]%3,r,wa[i],wb[j])?wa[i++]:wb[j++];
        for(;i<ta;p++) sa[p]=wa[i++];
        for(;j<tbc;p++) sa[p]=wb[j++];
        return;
    }
    void calheight(int *r, int *sa, int n)
    {
        int i, j, k = 0;
        for (i = 1; i <= n; ++i) rank[sa[i]] = i;
        for (i = 0; i < n; height[rank[i++]] = k)
            for (k ? k-- : 0, j = sa[rank[i] - 1]; r[i + k] == r[j + k]; ++k);
        return;
    }
    int main()
    {
        int t;
        scanf("%d",&t);
        while(t--){
            scanf("%s",s);
            int Max=-1;
            n=strlen(s);
            for(int i=0;i<n;i++){  r[i]=s[i];  if(r[i]>Max)Max=r[i]; }
            r[n]=0;
            dc3(r,sa,n+1,Max+1);
            calheight(r,sa,n);
            ll sum=0;
            for(int i=2;i<=n;i++)sum+=height[i];
            printf("%lld
    ",1ll*(1+n)*n/2-sum);
        }
        return 0;
    }
    DC3版本

    KMP算法 

    KMP模板 (next[0]=-1) next[i] 的值是  (1~i-1)  的后缀和  (0-i-1) 的前缀   相同字串

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1e6+10;
    char ss[maxn],tt[maxn];
    int  nt[maxn];
    void get_next(char *tt){
        int l=strlen(tt);
        nt[0]=-1;
        int j=0,k=-1;
        while(j<l){
            if(k==-1 || tt[j]==tt[k]) nt[++j]=++k;
            else k=nt[k];
        }
    }
    int KMP(char *ss,char *tt){   //  ss 文本串    tt 匹配串 <-nt
        get_next(tt);
        int ls=strlen(ss);
        int lt=strlen(tt);
        int i=0,j=0;
        while(i<ls && j<lt){
            if(j==-1 || ss[i]==tt[j]){
                i++; j++;
            }
            else j=nt[j];
            if(j==lt) return i-lt+1;
        }
        return -1;
    }
    int main(){
    
    }
    View Code

    洛谷 KMP 模板 (两种写法)

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1e6+10;
    int  nt[maxn];
    vector<int> vs;
    void get_next(char *tt){
        int l=strlen(tt);
        nt[0]=-1;
        int j=0,k=-1;
        while(j<l){
            if(k==-1 || tt[j]==tt[k]) nt[++j]=++k;
            else k=nt[k];
        }
    }
    void KMP(char *ss,char *tt){   //  ss 文本串    tt 匹配串 <-nt
        get_next(tt);
        int ls=strlen(ss);
        int lt=strlen(tt);
        int i=0,j=0;
        while(i<ls && j<lt){
            if(j==-1 || ss[i]==tt[j]){
                i++; j++;
            }
            else j=nt[j];
            if(j==lt) { vs.push_back(i-lt+1);j=nt[j];  }
        }
    }
    char ss[maxn],tt[maxn];
    int main(){
        cin>>ss;
        cin>>tt;
        int l=strlen(tt);
        KMP(ss,tt);
        for(int i=0;i<vs.size();i++) cout<<vs[i]<<endl;
        for(int i=1;i<=l;i++){  if(i!=1) cout<<" ";  cout<<nt[i];  } cout<<endl;
    }
    View Code
    #include<bits/stdc++.h>
    using namespace std;
    int  nt[1000005];
    char tt[1000005];
    char ss[1000005];
    int KMP(char *ss,char *tt){
        int t=strlen(tt);
        nt[0]=-1;
        for (int i = 1; i < t; ++i) {
            int j = nt[i-1];
            while(tt[j+1] != tt[i] && j >= 0) j = nt[j];
            if(tt[j+1] == tt[i]) nt[i] = j+1;
            else nt[i] = -1;
        }
        int s=strlen(ss);
        int i=0,j=0;
        while(i<s){
            if(ss[i]==tt[j]){
                i++;  j++;
                if(j==t){
                    printf("%d
    ",i-t+1);
                    j=nt[j-1]+1;
                }
            }
            else {
                if(j==0)i++;
                else    j=nt[j-1]+1;
            }
        }
    }
    int main(){
       cin>>tt; cin>>ss;
       int ls=strlen(ss);  int num=KMP(tt,ss);
       for(int i=0;i<ls;i++){
          if(i!=0) cout<<" ";
         cout<<nt[i]+1;
       }cout<<endl;
    }
    View Code

    数组tt  在   数组ss 第一次出现的位置   (next[0]=-1); 

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1e6+10;
    int ss[maxn],tt[maxn];
    int  nt[maxn];
    int  n,m;
    void get_next(){
        int l=m;
        nt[0]=-1;
        int j=0,k=-1;
        while(j<l){
            if(k==-1 || tt[j]==tt[k]) nt[++j]=++k;
            else k=nt[k];
        }
    }
    int KMP(){   //  ss 文本串    tt 匹配串 <-nt
        get_next();
        int ls=n;
        int lt=m;
        int i=0,j=0;
        while(i<ls && j<lt){
            if(j==-1 || ss[i]==tt[j]){
                i++; j++;
            }
            else j=nt[j];
            if(j==lt) return i-lt+1;
        }
        return -1;
    }
    int main(){
       int T; scanf("%d",&T);
       while(T--){
           scanf("%d %d",&n,&m);
           for(int i=0;i<n;i++) scanf("%d",&ss[i]);
           for(int i=0;i<m;i++) scanf("%d",&tt[i]);
           printf("%d
    ",KMP());
           for(int i=0;i<m;i++) nt[i]=0;
       }
    }
    View Code

     字符串tt  在 字符串ss中出现的次数

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1e6+10;
    int  nt[maxn];
    void get_next(char *tt){
        int l=strlen(tt);
        nt[0]=-1;
        int j=0,k=-1;
        while(j<l){
            if(k==-1 || tt[j]==tt[k]) nt[++j]=++k;
            else k=nt[k];
        }
    }
    int KMP(char *ss,char *tt){   //  ss 文本串    tt 匹配串 <-nt
        get_next(tt);
        int ls=strlen(ss);
        int lt=strlen(tt);
        int i=0,j=0;
        int num=0;
        while(i<ls && j<lt){
            if(j==-1 || ss[i]==tt[j]){
                i++; j++;
            }
            else j=nt[j];
            if(j==lt) { num++; j=nt[j];  }
        }
        return num;
    }
    char ss[maxn],tt[maxn];
    int main(){
        int T; scanf("%d",&T);
        while(T--){
            scanf("%s",tt); scanf("%s",ss);
            int x=KMP(ss,tt);
            printf("%d
    ",x);
        }
    }
    View Code

     字符串tt  在 字符串ss中出现的次数 (不重叠)

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1e6+10;
    int  nt[maxn];
    void get_next(char *tt){
        int l=strlen(tt);
        nt[0]=-1;
        int j=0,k=-1;
        while(j<l){
            if(k==-1 || tt[j]==tt[k]) nt[++j]=++k;
            else k=nt[k];
        }
    }
    int KMP(char *ss,char *tt){   //  ss 文本串    tt 匹配串 <-nt
        get_next(tt);
        int ls=strlen(ss);
        int lt=strlen(tt);
        int i=0,j=0;
        int num=0;
        while(i<ls && j<lt){
            if(j==-1 || ss[i]==tt[j]){
                i++; j++;
            }
            else j=nt[j];
            if(j==lt) { num++; j=0;  }
        }
        return num;
    }
    char ss[maxn],tt[maxn];
    int main(){
        while(1){
            scanf("%s",tt);
            if(tt[0]=='#') break;
            scanf("%s",ss);
            int x=KMP(tt,ss);
            printf("%d
    ",x);
        }
    }
    View Code

    EXKMP    有两个字符串aa,bb,要求输出bb与aa的每一个后缀的最长公共前缀

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1e6+10;
    char ss[maxn],tt[maxn];
    int  p[maxn], ex[maxn];
    void EXKMP(char *ss,char *tt){  // ss 文本串  tt匹配串
        int ls=strlen(ss+1),lt=strlen(tt+1);
        p[1]=lt;  int j=1;  while(tt[j]==tt[j+1] && j+1<=lt) j++;
        p[2]=j-1; // 2-n  1-n 的最长公共前缀;
        int k=2;  //         最长匹配的下标
        for(int i=3;i<=lt;i++){
            int pp=k+p[k]-1;     //
            int L=p[i-k+1];      //
            if(i-k+L<pp-k+1){  p[i]=L; }
            else if(i-k+L>=pp-k+1){
                int j=pp-i+1; if(j<0) j=0;
                while(tt[j+1] == tt[i+j] && i+j<=lt) j++;
                p[i]=j;
                k=i;
            }
        }
        j=1;
        while(ss[j]==tt[j] && j<=ls && j<=lt) j++;
        ex[1]=j-1;
        k=1;
        for(int i=2;i<=ls;i++){
            int pp=ex[k]+k-1;
            int L=p[i-k+1];
            if(i-k+L<pp-k+1){ ex[i]=L; }
            else if(i-k+L>=pp-k+1){
                int j=pp-i+1; if(j<0) j=0;
                while(tt[j+1]==ss[i+j] && i+j<=ls && j+1<=lt ) j++;
                ex[i]=j;
                k=i;
            }
        }
    }
    int main(){
        scanf("%s",ss+1);  scanf("%s",tt+1);
        int ls=strlen(ss+1);  int lt=strlen(tt+1);
        EXKMP(ss,tt);
        for(int i=1;i<=lt;i++){  if(i!=1) cout<<" "; cout<<p[i]; }cout<<endl;
        for(int i=1;i<=ls;i++){  if(i!=1) cout<<" "; cout<<ex[i];}cout<<endl;
    }
    View Code

     hd2594   找aa的最长前缀是bb的后缀

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1e6+10;
    char ss[maxn],tt[maxn];
    int  p[maxn], ex[maxn];
    void EXKMP(char *ss,char *tt){  // ss 文本串  tt匹配串
        int ls=strlen(ss+1),lt=strlen(tt+1);
        p[1]=lt;  int j=1;  while(tt[j]==tt[j+1] && j+1<=lt) j++;
        p[2]=j-1; // 2-n  1-n 的最长公共前缀;
        int k=2;  //         最长匹配的下标
        for(int i=3;i<=lt;i++){
            int pp=k+p[k]-1;     //
            int L=p[i-k+1];      //
            if(i-k+L<pp-k+1){  p[i]=L; }
            else if(i-k+L>=pp-k+1){
                int j=pp-i+1; if(j<0) j=0;
                while(tt[j+1] == tt[i+j] && i+j<=lt) j++;
                p[i]=j;
                k=i;
            }
        }
        j=1;
        while(ss[j]==tt[j] && j<=ls && j<=lt) j++;
        ex[1]=j-1;
        k=1;
        for(int i=2;i<=ls;i++){
            int pp=ex[k]+k-1;
            int L=p[i-k+1];
            if(i-k+L<pp-k+1){ ex[i]=L; }
            else if(i-k+L>=pp-k+1){
                int j=pp-i+1; if(j<0) j=0;
                while(tt[j+1]==ss[i+j] && i+j<=ls && j+1<=lt ) j++;
                ex[i]=j;
                k=i;
            }
        }
    }
    int main(){
    while(scanf("%s",tt+1)!=EOF){
        scanf("%s",ss+1);
        int ls=strlen(ss+1);
        int lt=strlen(tt+1);
        EXKMP(ss,tt);
        int ans=0;
        for(int i=1;i<=ls;i++){
            if(i+ex[i]-1==ls)  ans=max(ans,ex[i]);
        }
        if(ans==0){
            printf("0
    ");
        }
        else {
            for(int i=1;i<=ls;i++){
                if(ex[i]==ans && i+ex[i]-1==ls){
                    for(int j=i;j<i+ex[i];j++){
                        printf("%c",ss[j]);
                    }
                    break;
                }
            }
            printf(" %d
    ",ans);
        }
    }
    }
    View Code

    AC自动机 模板  (初始化  插入   构建 查询   清空)

    #include<bits/stdc++.h>
    using namespace std;
    struct AC{
        static const int maxn=1e6+10;
        static const int MAXN=maxn;
        static const int ls=26;
        #define ll long long
        #define LL long long
        int ch[maxn][ls],fail[maxn],val[maxn];
        int tot=0;
        queue<int> q;
        void init(){
            tot=0;
        }
        void Insert(char *ss){  // 构建字典树
            int now=0;
            int l=strlen(ss);
            for(int i=0;i<l;i++){  int x=ss[i]-'a';
                if(!ch[now][x])  ch[now][x]=++tot;
                now=ch[now][x];
            }  val[now]++;    // 统计字符出现的次数
        }
        void fail_tree(){  // 字典树上fail指针   (链上后缀  前缀比较)
            for(int i=0;i<ls;i++){
                if(ch[0][i]){  fail[ch[0][i]]=0; q.push(ch[0][i]); }
            }
            while(!q.empty()){
                int x=q.front(); q.pop();
                for(int i=0;i<ls;i++){
                    if(ch[x][i]){
                        fail[ch[x][i]]=ch[fail[x]][i]; q.push(ch[x][i]);
                    }
                    else ch[x][i]=ch[fail[x]][i];  //   匹配失败  转 next
                }
            }
        }
        int Find(char *ss){
            int l=strlen(ss);
            int now=0;  int ans=0;
            for(int i=0;i<l;i++){
                int x=ss[i]-'a';
                now=ch[now][x];
                for(int j=now;j&&val[j];j=fail[j]){
                    ans+=val[j];
                    val[j]=0;
                }
            }
            return ans;
        }
        void clear(){
            for(int i=0;i<=tot;i++){
                fail[i]=0; val[i]=0;
                for(int j=0;j<ls;j++)  ch[i][j]=0;
            }
        }
    }ac;
    const int maxn=1e6+10;
    char ss[maxn];
    int main(){
        
    }
    View Code

    洛谷  P3808   模式串在 文本串中出现的个数

    #include<bits/stdc++.h>
    using namespace std;
    struct AC{
        static const int maxn=1e6+10;
        static const int MAXN=maxn;
        static const int ls=26;
        #define ll long long
        #define LL long long
        int ch[maxn][ls],fail[maxn],val[maxn];
        int tot=0;
        queue<int> q;
        void Insert(char *ss){  // 构建字典树
            int now=0;
            int l=strlen(ss);
            for(int i=0;i<l;i++){  int x=ss[i]-'a';
                if(!ch[now][x])  ch[now][x]=++tot;
                now=ch[now][x];
            }  val[now]++;    // 统计字符出现的次数
        }
        void fail_tree(){  // 字典树上fail指针   (链上后缀  前缀比较)
            for(int i=0;i<ls;i++){
                if(ch[0][i]){  fail[ch[0][i]]=0; q.push(ch[0][i]); }
            }
            while(!q.empty()){
                int x=q.front(); q.pop();
                for(int i=0;i<ls;i++){
                    if(ch[x][i]){
                        fail[ch[x][i]]=ch[fail[x]][i]; q.push(ch[x][i]);
                    }
                    else ch[x][i]=ch[fail[x]][i];  //   匹配失败  转 next
                }
            }
        }
        int Find(char *ss){
            int l=strlen(ss);
            int now=0;  int ans=0;
            for(int i=0;i<l;i++){
                int x=ss[i]-'a';
                now=ch[now][x];
                for(int j=now;j&&val[j];j=fail[j]){
                    ans+=val[j];
                    val[j]=0;
                }
            }
            return ans;
        }
    }ac;
    const int maxn=1e6+10;
    char ss[maxn];
    int main(){
        int n; scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%s",ss); ac.Insert(ss);
        }
        ac.fail_tree();
        scanf("%s",ss);
        printf("%d
    ",ac.Find(ss));
    }
    View Code

     洛谷 P3496  输出 出现次数最多的模式串  AC 自动机 fail 指针的拓扑排序 不是 1-tot  同后缀自动机

    #include<bits/stdc++.h>
    using namespace std;
    struct AC{
        static const int maxn=1e6+10;
        static const int MAXN=maxn;
        static const int ls=26;
        #define ll long long
        #define LL long long
        int ch[maxn][ls],fail[maxn],val[maxn];
        int tot=0;
        queue<int> q;
        void init(){  tot=0;  }
        int Insert(char *ss){  // 构建字典树
            int now=0;
            int l=strlen(ss);
            for(int i=0;i<l;i++){  int x=ss[i]-'a';
                if(!ch[now][x])  ch[now][x]=++tot;
                now=ch[now][x];
            }
            return now;
        }
        void fail_tree(){  // 字典树上fail指针   (链上后缀  前缀比较)
            for(int i=0;i<ls;i++){
                if(ch[0][i]){  fail[ch[0][i]]=0; q.push(ch[0][i]); }
            }
            while(!q.empty()){
                int x=q.front(); q.pop();
                for(int i=0;i<ls;i++){
                    if(ch[x][i]){
                        fail[ch[x][i]]=ch[fail[x]][i]; q.push(ch[x][i]);
                    }
                    else ch[x][i]=ch[fail[x]][i];  //   匹配失败  转 next
                }
            }
        }
        void Find(char *ss){
            int l=strlen(ss);
            int now=0;  int ans=0;
            for(int i=0;i<l;i++){
                int x=ss[i]-'a';
                now=ch[now][x];
                val[now]++;
            }
        }
        vector<int> vs[maxn];
        void dfs(int x){
            for(int i=0;i<vs[x].size();i++){
                dfs(vs[x][i]);
                val[x]+=val[vs[x][i]];
            }
        }
        void make(){
            for(int i=1;i<=tot;i++)  vs[fail[i]].push_back(i);
            dfs(0);
        }
        void work(){
            make();
            //for(int i=tot;i>=1;i--){  val[fail[i]]+=val[i];  }
        }
        void clear(){
            for(int i=0;i<=tot;i++){
                fail[i]=0; val[i]=0; vs[i].clear();
                for(int j=0;j<ls;j++)  ch[i][j]=0;
            }
        }
    }ac;
    const int maxn=1e6+10;
    char ss[160][210];
    char tt[maxn];
    int pos[maxn];
    int main(){
        while(1){
            int n; scanf("%d",&n);
            if(n==0) break;
            ac.init();
            for(int i=1;i<=n;i++){
                scanf("%s",ss[i]);  pos[i]=ac.Insert(ss[i]);
            }ac.fail_tree();
            scanf("%s",tt);  ac.Find(tt);  ac.work();
            int temp=0;
            for(int i=1;i<=n;i++){
                temp=max(temp,ac.val[pos[i]]);
            }
            printf("%d
    ",temp);
            for(int i=1;i<=n;i++){
                if(ac.val[pos[i]]==temp) printf("%s
    ",ss[i]);
            }
            ac.clear();
        }
    }
    View Code

     洛谷 P5357  模式串出现次数  

    #include<bits/stdc++.h>
    using namespace std;
    struct AC{
        static const int maxn=2e6+10;
        static const int MAXN=maxn;
        static const int ls=26;
        #define ll long long
        #define LL long long
        int ch[maxn][ls],fail[maxn],val[maxn];
        int tot=0;
        queue<int> q;
        void init(){  tot=0;  }
        int Insert(char *ss){  // 构建字典树
            int now=0;
            int l=strlen(ss);
            for(int i=0;i<l;i++){  int x=ss[i]-'a';
                if(!ch[now][x])  ch[now][x]=++tot;
                now=ch[now][x];
            }
            return now;
        }
        void fail_tree(){  // 字典树上fail指针   (链上后缀  前缀比较)
            for(int i=0;i<ls;i++){
                if(ch[0][i]){  fail[ch[0][i]]=0; q.push(ch[0][i]); }
            }
            while(!q.empty()){
                int x=q.front(); q.pop();
                for(int i=0;i<ls;i++){
                    if(ch[x][i]){
                        fail[ch[x][i]]=ch[fail[x]][i]; q.push(ch[x][i]);
                    }
                    else ch[x][i]=ch[fail[x]][i];  //   匹配失败  转 next
                }
            }
        }
        void Find(char *ss){
            int l=strlen(ss);
            int now=0;  int ans=0;
            for(int i=0;i<l;i++){
                int x=ss[i]-'a';
                now=ch[now][x];
                val[now]++;
            }
        }
        vector<int> vs[maxn];
        void dfs(int x){
            for(int i=0;i<vs[x].size();i++){
                dfs(vs[x][i]);
                val[x]+=val[vs[x][i]];
            }
        }
        void make(){
            for(int i=1;i<=tot;i++)  vs[fail[i]].push_back(i);
            dfs(0);
        }
        void work(){
            make();
            //for(int i=tot;i>=1;i--){  val[fail[i]]+=val[i];  }
        }
        void clear(){
            for(int i=0;i<=tot;i++){
                fail[i]=0; val[i]=0; vs[i].clear();
                for(int j=0;j<ls;j++)  ch[i][j]=0;
            }
        }
    }ac;
    const int maxn=2e6+10;
    char ss[maxn];
    char tt[maxn];
    int pos[maxn];
    int main(){
        int n; scanf("%d",&n);
        ac.init();
        for(int i=1;i<=n;i++){
            scanf("%s",ss);  pos[i]=ac.Insert(ss);
        }ac.fail_tree();
        scanf("%s",tt);  ac.Find(tt);  ac.work();
        int temp=0;
        for(int i=1;i<=n;i++){
            temp=ac.val[pos[i]];
            printf("%d
    ",temp);
        }
    
    }
    View Code

     hdu 2896     多模式串  多匹配串

    #include<bits/stdc++.h>
    using namespace std;
    vector<pair<int,int> > vs;
    struct AC{
        static const int maxn=1e5+10;
        static const int MAXN=maxn;
        static const int ls=128;
        #define ll long long
        #define LL long long
        int fail[maxn],val[maxn];
        int ch[maxn][ls];
        int tot=0;
        queue<int> q;
        void init(){ tot=0; }
        void Insert(char *ss,int k){  // 构建字典树
            int now=0;
            int l=strlen(ss);
            for(int i=0;i<l;i++){  int x=ss[i];
                if(!ch[now][x])  ch[now][x]=++tot;
                now=ch[now][x];
            }  val[now]=k;    // 统计字符出现的次数
        }
        void fail_tree(){  // 字典树上fail指针   (链上后缀  前缀比较)
            for(int i=0;i<ls;i++){
                if(ch[0][i]){  fail[ch[0][i]]=0; q.push(ch[0][i]); }
            }
            while(!q.empty()){
                int x=q.front(); q.pop();
                for(int i=0;i<ls;i++){
                    if(ch[x][i]){
                        fail[ch[x][i]]=ch[fail[x]][i]; q.push(ch[x][i]);
                    }
                    else ch[x][i]=ch[fail[x]][i];  //   匹配失败  转 next
                }
            }
        }
        void Find(char *ss){
            int l=strlen(ss);
            int now=0;  int ans=0;
            for(int i=0;i<l;i++){
                int x=ss[i];
                now=ch[now][x];
                for(int j=now;j&&val[j];j=fail[j]){
                    if(val[j]) vs.push_back({val[j],j});
                    val[j]=0;
                }
            }
        }
        void clear(){
            for(int i=0;i<=tot;i++){
                fail[i]=0; val[i]=0;
                for(int j=0;j<ls;j++)  ch[i][j]=0;
            }
        }
    }ac;
    const int maxn=1e6+10;
    char ss[maxn];
    int main(){
        int n; scanf("%d",&n);
        ac.init();
        int k=0;
        for(int i=1;i<=n;i++){ scanf("%s",ss); ac.Insert(ss,i); }
        ac.fail_tree();
        int m; scanf("%d",&m);
        for(int i=1;i<=m;i++){
            scanf("%s",ss); ac.Find(ss);
            sort(vs.begin(),vs.end());
            if(vs.size()==0) continue;
            printf("web %d:",i);
            for(int i=0;i<vs.size();i++){
                printf(" %d",vs[i].first);
                ac.val[vs[i].second]=vs[i].first;
            }
            printf("
    ");
            if(vs.size()) k++;
            vs.clear();
        }
        printf("total: %d
    ",k);
    }
    View Code

     poj 2778     AC自动机 + 矩阵快速幂

    #include<stdio.h>
    #include<string>
    #include<cstring>
    #include<vector>
    #include<queue>
    #define ll long long
    #define LL long long
    using namespace std;
    vector<int> vs;
    const int mod=100000;
    const int MOD=mod;
    struct Matrix {
        ll a[105][105];
        void init() {
            for (int i = 0; i < 105; i++) {
                for (int j = 0; j < 105; j++)
                    a[i][j] = 0;
            }
        }
        void _init() {
            init();
            for (int i = 0; i < 105; i++) a[i][i] = 1;
        }
    }A, B;
    
    Matrix mul(Matrix a, Matrix b) {
        Matrix ans;
        ans.init();
        for (int i = 0; i < 105; i++) {
            for (int j = 0; j < 105; j++) {
                if(a.a[i][j]) {
                    for (int k = 0; k < 105; k++) ans.a[i][k] = (ans.a[i][k] + 1LL * a.a[i][j] * b.a[j][k]) % MOD;
                }
            }
        }
        return ans;
    }
    void make(Matrix &A){
        for(int i=0;i<vs.size();i++){
            int x=vs[i];
            for(int j=0;j<105;j++){
                A.a[x][j]=0;
                A.a[j][x]=0;
            }
        }
    }
    Matrix q_pow(Matrix a, int k) {
        Matrix ans;
        ans._init();
        if(k <= 0) return ans;
        while(k) {
            if(k&1) ans = mul(ans, a);
            a = mul(a, a);
            k >>= 1;
        }
        return ans;
    }
    struct AC{
        static const int maxn=1e6+10;
        static const int MAXN=maxn;
        static const int ls=4;
        #define ll long long
        #define LL long long
        int ch[maxn][ls],fail[maxn], val[maxn];
        int tot;
        queue<int> q;
        void init(){ tot=0;}
        void Insert(char *ss){  // 构建字典树
            int now=0;
            int l=strlen(ss);
            for(int i=0;i<l;i++){
                int x;
                if(ss[i]=='A') x=0;
                else if(ss[i]=='T') x=1;
                else if(ss[i]=='G') x=2;
                else x=3;
                if(!ch[now][x])  ch[now][x]=++tot;
                now=ch[now][x];
            }  val[now]++;    // 统计字符出现的次数
            vs.push_back(now);
        }
        void fail_tree(){  // 字典树上fail指针   (链上后缀  前缀比较)
            for(int i=0;i<ls;i++){
                if(ch[0][i]){fail[ch[0][i]]=0; q.push(ch[0][i]); }
            }
            while(!q.empty()){
                int x=q.front(); q.pop();
                if(val[fail[x]]){
                    vs.push_back(x);
                    val[x]++;
                }
                for(int i=0;i<ls;i++){
                    if(ch[x][i]){
                        fail[ch[x][i]]=ch[fail[x]][i];
                        q.push(ch[x][i]);
                    }
                    else {
                         ch[x][i]=ch[fail[x]][i];  //   匹配失败  转 next
                    }
                }
            }
        }
        void work(int x){
            A.init();
            B.init();
            A.a[0][0]=1;  //
            for(int i=0;i<=tot;i++){
                for(int j=0;j<ls;j++){
                    int y=ch[i][j];  B.a[i][y]++;
                }
            }
            make(B);
            A=mul(A,q_pow(B,x));
            ll ans=0;
            for(int i=0;i<105;i++){
                for(int j=0;j<105;j++){
                    ans+=A.a[i][j];
                }
            }
            ans%=mod;
            printf("%lld
    ",ans);
    
        }
        void clear(){
            for(int i=0;i<=tot;i++){
                fail[i]=0; val[i]=0;
                for(int j=0;j<ls;j++)  ch[i][j]=0;
            }
        }
    }ac;
    const int maxn=1e6+10;
    char ss[maxn];
    int main(){
        int n,m; scanf("%d %d",&n,&m);
        ac.init();
        for(int i=1;i<=n;i++){
            scanf("%s",ss); ac.Insert(ss);
        }
        ac.fail_tree();
        ac.work(m);
        ac.clear();
    }
    /*
    4 3
    AT
    AC
    AG
    AA
    */
    View Code

     hdu 2243  AC自动机  + 等比数列(矩阵优化) + 矩阵等比 (矩阵优化)

    #include<bits/stdc++.h>
    #define ll long long
    #define LL long long
    using namespace std;
    vector<int> vs;
    struct Matrix {
        unsigned long long   a[105][105];
        void init() {
            for (int i = 0; i < 105; i++) {
                for (int j = 0; j < 105; j++)
                    a[i][j] = 0;
            }
        }
        void _init() {
            init();
            for (int i = 0; i < 105; i++) a[i][i] = 1;
        }
    }A, B,C,D;
    
    Matrix mul(Matrix a, Matrix b) {
        Matrix ans;
        ans.init();
        for (int i = 0; i < 105; i++) {
            for (int j = 0; j < 105; j++) {
                if(a.a[i][j]) {
                    for (int k = 0; k < 105; k++) ans.a[i][k] = (ans.a[i][k] +  a.a[i][j] * b.a[j][k]) ;
                }
            }
        }
        return ans;
    }
    void make(Matrix &A){
        for(int i=0;i<vs.size();i++){
            int x=vs[i];
            for(int j=0;j<105;j++){
                A.a[x][j]=0;
                A.a[j][x]=0;
            }
        }
    }
    Matrix q_pow(Matrix a,  int k) {
        Matrix ans;
        ans._init();
        if(k <= 0) return ans;
        while(k) {
            if(k&1) ans = mul(ans, a);
            a = mul(a, a);
            k >>= 1;
        }
        return ans;
    }
    /*unsigned int quick(unsigned int  x,ll n){
        unsigned int ans=1;
        while(n){
            if(n&1)  ans=ans*x;
            x=x*x;
            n=n/2;
        }  cout<<ans<<endl;
        return ans;
    }*/
    struct AC{
        static const int maxn=1e6+10;
        static const int MAXN=maxn;
        static const int ls=26;
        #define ll long long
        #define LL long long
        int ch[maxn][ls],fail[maxn], val[maxn];
        int tot;
        queue<int> q;
        void init(){ tot=0;}
        void Insert(char *ss){  // 构建字典树
            int now=0;
            int l=strlen(ss);
            for(int i=0;i<l;i++){
                int x=ss[i]-'a';
                if(!ch[now][x])  ch[now][x]=++tot;
                now=ch[now][x];
            }  val[now]++;    // 统计字符出现的次数
            vs.push_back(now);
        }
        void fail_tree(){  // 字典树上fail指针   (链上后缀  前缀比较)
            for(int i=0;i<ls;i++){
                if(ch[0][i]){fail[ch[0][i]]=0; q.push(ch[0][i]); }
            }
            while(!q.empty()){
                int x=q.front(); q.pop();
                if(val[fail[x]]){
                    vs.push_back(x);
                    val[x]++;
                }
                for(int i=0;i<ls;i++){
                    if(ch[x][i]){
                        fail[ch[x][i]]=ch[fail[x]][i];
                        q.push(ch[x][i]);
                    }
                    else {
                         ch[x][i]=ch[fail[x]][i];  //   匹配失败  转 next
                    }
                }
            }
        }
        void work(int x){
            A.init(); B.init(); C.init();  D.init();
            A.a[0][0]=1;
            for(int i=0;i<=tot;i++){
                for(int j=0;j<ls;j++){
                    int y=ch[i][j];  B.a[i][y]++;
                }
            }
            make(B);
            for(int i=0;i<=tot;i++){
                for(int j=0;j<=tot;j++){
                    C.a[i][j]=B.a[i][j];        //B
                    if(i==j) C.a[i][j+tot+1]=1; // E
                    else     C.a[i][j+tot+1]=0;
                }
            }
            for(int i=0;i<=tot;i++){
                for(int j=0;j<=tot;j++){
                    if(i==j) C.a[i+tot+1][j+tot+1]=1; // E
                    else     C.a[i+tot+1][j+tot+1]=0;
                    C.a[i+tot+1][j]=0;
                }
            }
            D.a[0][0]=26; D.a[0][1]=1;  D.a[1][0]=0;  D.a[1][1]=1;
            D=q_pow(D,x);
            C=q_pow(C,x);
            B.init();
            for(int i=0;i<=tot;i++){
                for(int j=0;j<=tot;j++){
    B.a[i][j]=C.a[i][j]+C.a[i][j+tot+1]+C.a[i+tot+1][j]-C.a[i+tot+1][j+tot+1];
                }
            }
            A=mul(A,B);
             unsigned long long ans=D.a[0][0]+D.a[0][1]+D.a[1][0]-D.a[1][1];
            for(int i=0;i<=tot;i++){
                for(int j=0;j<=tot;j++){
                    ans-=A.a[i][j];
                }
            }
            printf("%llu
    ",ans);
    
        }
        void clear(){
            for(int i=0;i<=tot;i++){
                fail[i]=0; val[i]=0;
                for(int j=0;j<ls;j++)  ch[i][j]=0;
            }
            vs.clear();
        }
    }ac;
    const int maxn=1e6+10;
    char ss[maxn];
    int main(){
        int n,m;
        while(~scanf("%d %d",&n,&m)){
            ac.init();
            for(int i=1;i<=n;i++){ scanf("%s",ss); ac.Insert(ss); }
            ac.fail_tree();
            ac.work(m);
            ac.clear();
        }
        return 0;
    }
    /*
    3
    AT
    AC
    AG
    AA
    */
    View Code

     hdu 4511  AC自动机  + dp  + 最短路    //  可以优化个n  分层跑

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int maxn=1e6+10;
    pair<double,double> pa[maxn];
    vector<int> vs;
    double dis(int x,int y){
        return sqrt( (pa[x].first-pa[y].first)*(pa[x].first-pa[y].first)
                    +(pa[x].second-pa[y].second)*(pa[x].second-pa[y].second) );
    }
    struct AC{
        static const int maxn=2000+10;
        static const int MAXN=maxn;
        static const int ls=51;
        #define ll long long
        #define LL long long
        int ch[maxn][ls],fail[maxn],val[maxn];
        double dp[maxn][ls];
        int mp[maxn];
        int tot=0;
        queue<int> q;
        vector<int> p;
        void init(){
            tot=0;  mp[0]=0; // --> point
            for(int i=0;i<maxn;i++){
                for(int j=0;j<ls;j++){
                    dp[i][j]=1e18;
                }
            }
        }
        void Insert(vector<int> vs){  // 构建字典树
            int now=0;
            int l=vs.size();
            for(int i=0;i<l;i++){  int x=vs[i];
                if(!ch[now][x])  { ch[now][x]=++tot; mp[tot]=x;}// ->point  }
                now=ch[now][x];
            }  val[now]++;    // 统计字符出现的次数
        }
        void fail_tree(int n){  // 字典树上fail指针   (链上后缀  前缀比较)
            p.push_back(0); // bfs 序列
            for(int i=0;i<n;i++){
                if(ch[0][i]){  fail[ch[0][i]]=0; q.push(ch[0][i]); p.push_back(ch[0][i]);  }
            }
            while(!q.empty()){
                int x=q.front(); q.pop();
                if(val[fail[x]] ) { val[x]++;  }  // limit
                for(int i=0;i<n;i++){
                    if(ch[x][i]){
                        fail[ch[x][i]]=ch[fail[x]][i]; q.push(ch[x][i]); p.push_back(ch[x][i]);
                    }
                    else ch[x][i]=ch[fail[x]][i];  //   匹配失败  转 next
                }
            }
        }
        void slove(int n){
            int T=1;
            if(ch[0][0]) { dp[ch[0][0]][0]=0;  }
            else         { dp[0][0]=0; }
           // cout<<p.size()<<endl;
            while(T--){
                for(int i=0;i<p.size();i++){
                    int x=p[i];  if(val[x]) continue;
                   // cout<<x<<"==="<<mp[x]<<endl;
                    if(x==0){
                        for(int j=0;j<n;j++){
                            for(int k=j+1;k<n;k++){
                                int pos=ch[x][k];
                                if(val[pos]) continue;
                                dp[pos][k]=min(dp[pos][k],dp[x][j]+dis(j,k));
                              // cout<<pos<<" "<<k<<" "<<" "<<j<<" "<<dp[pos][k]<<endl;
                            }
                        }
                    }
                    else {
                        for(int j=mp[x]+1;j<n;j++){
                            int pos=ch[x][j];  //cout<<pos<<endl;
                             if(val[pos])  continue;
                            dp[pos][j]=min(dp[pos][j],dp[x][mp[x]]+dis(mp[x],j));
                           // cout<<pos<<" "<<j<<" "<<dp[pos][j]<<endl;
                        }
                    }
                } // break;
            }
            double ans=1e18;
            for(int i=0;i<=tot;i++){
                if(val[i]) continue;
                ans=min(dp[i][n-1],ans);
            }
            if(ans>1e17) printf("Can not be reached!
    ");
            else         printf("%.2f
    ",ans);
        }
        void clear(){
            p.clear();
            for(int i=0;i<=tot;i++){
                fail[i]=0; val[i]=0;  for(int j=0;j<ls;j++)  ch[i][j]=0;
            }
        }
    }ac;
    int main(){
        int n,m;
        while(~scanf("%d %d",&n,&m)){
            if(n==0 && m==0 ) break;
            for(int i=0;i<n;i++){scanf("%lf %lf",&pa[i].first,&pa[i].second); }
            ac.init();
            while(m--){
                int k; scanf("%d",&k); vs.clear();
                for(int j=1;j<=k;j++) {  int x; scanf("%d",&x); x--; vs.push_back(x); }
                ac.Insert(vs);
            }
            ac.fail_tree(n);
            ac.slove(n);
            ac.clear();
        }
        return 0;
    }
    View Code

    字符串匹配 shift-and  

    hdu 5972

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=5e6+10;
    char ss[maxn];
    bitset<1005> S[10],X;
    int main(){
        int n;
        while( ~scanf("%d",&n) ){
        //scanf("%d",&n);
            for(int i=0;i<=9;i++) S[i].reset();
            X.reset();
            for(int i=0;i<n;i++){
                int k; scanf("%d",&k);
                while(k--){ int x; scanf("%d",&x); S[x].set(i);  }
            }
            scanf("%s",ss);  int l=strlen(ss);
            for(int i=0;i<l;i++){
                X=(X<<1);
                X.set(0);
                X=X&S[ss[i]-'0'];
                if(X[n-1]){
                    char ttmp = ss[i+1];
                    ss[i+1] = '';
                    puts(ss+i+1-n);
                    ss[i+1] = ttmp;
                }
            }
        }
        return 0;
    }
    View Code

    最小表示法模板

    string s;
    int Min(string s) {
        int i = 0, j = 1, k = 0, n = s.size(), d;
        while(i < n && j < n && k < n) {
            d = s[(i+k)%n] - s[(j+k)%n];
            if(!d) k++;
            else {
                if(d > 0) i += k+1;
                else j += k+1;
                if(i == j) j++;
                k = 0;
            }
        }
        return min(i, j);
    }
    View Code
  • 相关阅读:
    css之position
    js之循环语句
    js之条件判断
    js之字典操作
    js之获取html标签的值
    5.15 牛客挑战赛40 C 小V和字符串 数位dp 计数问题
    5.21 省选模拟赛 luogu P4297 [NOI2006]网络收费 树形dp
    luogu P4525 自适应辛普森法1
    luogu P1784 数独 dfs 舞蹈链 DXL
    5.21 省选模拟赛 luogu P4207 [NOI2005]月下柠檬树 解析几何 自适应辛普森积分法
  • 原文地址:https://www.cnblogs.com/Andromeda-Galaxy/p/11517152.html
Copyright © 2011-2022 走看看