回文自动机模板


#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); } }
回文自动机 字符串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\n",a[l-1][r-1]); } } }
回文自动机 回文串权值问题


#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\n",pam.slove()); }
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('\n'); } 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\n",ans); for(int i=0;i<=n;i++) vs[i].clear(); // pam.clear(); } }
洛谷 最长双回文串


#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\n",x); }
洛谷 拉拉队排练


#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\n"); else printf("%lld\n",ans); }
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\n",ans); for(int i=0;i<=l;i++) a[i]=b[i]=sumb[i]=0; pam.clear(); } }
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("\n"); pam.clear(); } }
后缀自动机


#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\n",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(); } }
给定一个只包含小写字母的字符串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\n",sam.ans); }
本质不同字符串个数(模板题)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\n",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(); } }
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\n",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; }
两字符串的最长相同字串


#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\n",ans); }
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\n",dp[l-1]); } }
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("\n"); } }
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\n",a[i]); } return 0; }
多个字符串的最长公共子串长度 拓扑排序 后缀树上父子关系


#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\n",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(); }
后缀数组
最小表示法


#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\n",ans); } return 0; }