题目链接:hdu 5343 MZL's Circle Zhou
题意:
给你两个串A,B,问从A,B中选子串x,y,问x+y可以组成多少个不同的串,x和y可以为空。
题解:
贴一个官方的题解
1 #include<bits/stdc++.h> 2 #define mst(a,b) memset(a,b,sizeof(a)) 3 #define F(i,a,b) for(int i=(a);i<=(b);++i) 4 using namespace std; 5 using ll=unsigned long long; 6 7 const int N=1e5+7,tyn=26,M=N*2; 8 struct SAM{ 9 int tr[M][tyn],f[M],ml[M],ed,last,p,x,r,q; 10 int b[M],d[M]; ll cnt[M]; 11 inline int gid(char x){return x-'a';} 12 inline void nc(int s,int &p){ 13 ml[p=++ed]=s,f[ed]=cnt[ed]=0,mst(tr[ed],0); 14 } 15 void clear(){ed=0,nc(0,last);} 16 void add(int w){ 17 nc(ml[x=last]+1,p),last=p,cnt[p]=1; 18 while(x&&!tr[x][w])tr[x][w]=p,x=f[x]; 19 if(!x)f[p]=1; 20 else if(ml[x]+1==ml[q=tr[x][w]])f[p]=q; 21 else{ 22 nc(ml[x]+1,r),f[r]=f[q],f[p]=f[q]=r; 23 memcpy(tr[r],tr[q],sizeof(tr[r])); 24 while(x&&tr[x][w]==q)tr[x][w]=r,x=f[x]; 25 } 26 } 27 void upright(int mx=0){ 28 F(i,0,ed)d[i]=0; 29 F(i,1,ed)d[mx<ml[i]?mx=ml[i]:ml[i]]++; 30 F(i,1,mx)d[i]+=d[i-1]; 31 F(i,1,ed)b[d[ml[i]]--]=i; 32 } 33 void build(char *s){for(int i=1;s[i];i++)add(gid(s[i]));} 34 }sam[2]; 35 36 37 char s[N]; 38 int t; 39 40 void work() 41 { 42 for(int i=sam[1].ed;i;--i) 43 { 44 int x=sam[1].b[i]; 45 sam[1].cnt[x]=1; 46 F(j,0,25) 47 { 48 int v=sam[1].tr[x][j]; 49 if(v)sam[1].cnt[x]+=sam[1].cnt[v]; 50 } 51 } 52 } 53 54 void solve() 55 { 56 for(int i=sam[0].ed;i;--i) 57 { 58 int x=sam[0].b[i]; 59 sam[0].cnt[x]=0; 60 F(j,0,25) 61 { 62 int v=sam[0].tr[x][j]; 63 if(v)sam[0].cnt[x]+=sam[0].cnt[v]; 64 else sam[0].cnt[x]+=sam[1].cnt[sam[1].tr[1][j]]; 65 } 66 } 67 ll ans=sam[0].cnt[1];//x为空的时候已经统计过了 68 F(i,2,sam[0].ed)ans+=sam[0].ml[i]-sam[0].ml[sam[0].f[i]];//y为空的时候 69 printf("%llu ",ans+1);//+1表示x和y都为空的时候 70 } 71 72 int main(){ 73 scanf("%d",&t); 74 while(t--) 75 { 76 scanf("%s",s+1); 77 sam[0].clear(),sam[0].build(s),sam[0].upright(); 78 scanf("%s",s+1); 79 sam[1].clear(),sam[1].build(s),sam[1].upright(); 80 work();solve(); 81 } 82 return 0; 83 }