字符串题目

 回文自动机  马拉车 后缀自动机  后缀数组  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
原文地址:https://www.cnblogs.com/Andromeda-Galaxy/p/11517152.html