题目链接:hdu 4416 Good Article Good sentence
题意:
给你一个串A和n个串B,问你A有多少个子串不是这n个B的子串。
题解:
将A串建立后缀自动机,对于每个B串都拿去匹配一下,并记录后缀自动机中每个节点的最大匹配长度。
然后拓扑排序,更新每个节点的fail节点。最后对于每个节点的贡献就是ml[i]-max(is[i],mx[f[i]]) (is[i]是该节点的最大匹配长度)
1 #include<bits/stdc++.h> 2 #define F(i,a,b) for(int i=a;i<=b;++i) 3 #define mst(a,b) memset(a,b,sizeof(a)) 4 using namespace std; 5 6 const int N=1e5+7,tyn=26,M=N*2; 7 struct SAM{ 8 int tr[M][tyn],f[M],ml[M],ed,last,p,x,r,q; 9 int cnt[M],b[M],d[M],is[M]; 10 inline int gid(char x){return x-'a';} 11 inline void nc(int s,int &p){ 12 ml[p=++ed]=s,f[ed]=cnt[ed]=0,mst(tr[ed],0); 13 } 14 void clear(){ed=0,nc(0,last);} 15 void add(int w){ 16 nc(ml[x=last]+1,p),last=p,cnt[p]=1; 17 while(x&&!tr[x][w])tr[x][w]=p,x=f[x]; 18 if(!x)f[p]=1; 19 else if(ml[x]+1==ml[q=tr[x][w]])f[p]=q; 20 else{ 21 nc(ml[x]+1,r),f[r]=f[q],f[p]=f[q]=r; 22 memcpy(tr[r],tr[q],sizeof(tr[r])); 23 while(x&&tr[x][w]==q)tr[x][w]=r,x=f[x]; 24 } 25 } 26 void build(char *s){for(int i=1;s[i];i++)add(gid(s[i]));} 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 for(int i=ed;i;--i)if(f[b[i]])is[f[b[i]]]=max(is[f[b[i]]],is[b[i]]); 33 } 34 void go(char *s,int x=1) 35 { 36 int cl=0;//与s的匹配长度 37 for(int i=1;s[i];i++) 38 { 39 int w=gid(s[i]); 40 if(tr[x][w])x=tr[x][w],cl++; 41 else 42 { 43 while(x&&!tr[x][w])x=f[x]; 44 if(!x)cl=0,x=1;else cl=ml[x]+1,x=tr[x][w]; 45 } 46 is[x]=max(is[x],cl); 47 } 48 } 49 }sam; 50 51 char s[N]; 52 int t,n,cas; 53 long long ans; 54 55 int main() 56 { 57 scanf("%d",&t); 58 while(t--) 59 { 60 scanf("%d%s",&n,s+1),ans=0; 61 sam.clear(),sam.build(s); 62 F(i,1,sam.ed)sam.is[i]=0; 63 F(i,1,n)scanf("%s",s+1),sam.go(s); 64 sam.upright(); 65 F(i,1,sam.ed)if(sam.is[i]<sam.ml[i]) 66 ans+=sam.ml[i]-max(sam.is[i],sam.f[i]!=0?sam.ml[sam.f[i]]:0); 67 printf("Case %d: %lld ",++cas,ans); 68 } 69 return 0; 70 }