题目大意:给出n个原串,再给出m个查询串。求每个查询串出现在了多少原串中。
题解
直接对原串建一个广义SAM,然后把每一个原串放到SAM上跑一跑,记录一下每一个状态属于多少个原串,用$size$表示。这样的话查询串直接在SAM上跑,如果失配输出0,否则直接输出记录在上面的$size$就好了。
1 //minamoto 2 #include<cstdio> 3 #include<cstring> 4 #include<iostream> 5 using namespace std; 6 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++) 7 char buf[1<<21],*p1=buf,*p2=buf; 8 inline int read(){ 9 #define num ch-'0' 10 char ch;bool flag=0;int res; 11 while(!isdigit(ch=getc())) 12 (ch=='-')&&(flag=true); 13 for(res=num;isdigit(ch=getc());res=res*10+num); 14 (flag)&&(res=-res); 15 #undef num 16 return res; 17 } 18 char sr[1<<21],z[20];int C=-1,Z; 19 inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;} 20 inline void print(int x){ 21 if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x; 22 while(z[++Z]=x%10+48,x/=10); 23 while(sr[++C]=z[Z],--Z);sr[++C]=' '; 24 } 25 const int N=100005; 26 int fa[N<<1],ch[N<<1][26],sz[N<<1],l[N<<1],las[N<<1],len[N],s[N]; 27 int n,m,cnt=1,last=1,tot=0; 28 void ins(int c){ 29 int p=last,np=++cnt;last=np,l[np]=l[p]+1; 30 for(;p&&!ch[p][c];p=fa[p]) ch[p][c]=np; 31 if(!p) fa[np]=1; 32 else{ 33 int q=ch[p][c]; 34 if(l[p]+1==l[q]) fa[np]=q; 35 else{ 36 int nq=++cnt;l[nq]=l[p]+1; 37 memcpy(ch[nq],ch[q],sizeof(ch[q])); 38 fa[nq]=fa[q];fa[q]=fa[np]=nq; 39 for(;ch[p][c]==q;p=fa[p]) ch[p][c]=nq; 40 } 41 } 42 } 43 inline void update(int x,int y){ 44 for(;x&&las[x]!=y;x=fa[x]) 45 ++sz[x],las[x]=y; 46 } 47 int main(){ 48 n=read(),m=read(); 49 for(int i=1;i<=n;++i){ 50 last=1; 51 char ch; 52 while((ch=getc())!=' ') ins(s[++tot]=ch-'a'),++len[i]; 53 } 54 tot=0; 55 for(int i=1;i<=n;++i) 56 for(int j=1,x=1;j<=len[i];++j) 57 update(x=ch[x][s[++tot]],i); 58 while(m--){ 59 tot=0; 60 char c;bool flag=true;int x=1; 61 while((c=getc())!=' '&&c!=EOF){ 62 int k=c-'a'; 63 if(flag) 64 ch[x][k]?x=ch[x][k]:flag=false; 65 } 66 print(flag?sz[x]:0); 67 } 68 Ot(); 69 return 0; 70 }