题意
给出你n个字符串和q个查询,每个查询给出一个字符串s,对于每个查询你都要输出这个字符串s在上面多少个字符串中出现过。
分析
广义后缀自动机的裸题。建好SAM以后再跑一遍得到每个状态的ocu和las。然后对于每个查询的字符串,跑到那个状态然后输出那个状态的ocu就可以了。
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <iostream> 5 6 using namespace std; 7 const int maxn=201000; 8 struct state{ 9 int len,link,ocu,las; 10 int next[26]; 11 }st[maxn]; 12 int N,Q,n; 13 int last,cur,sz; 14 char s[maxn]; 15 string S[100000+5]; 16 void init(){ 17 sz=1; 18 cur=last=0; 19 st[0].link=-1; 20 st[0].len=0; 21 } 22 void build_sam(int c){ 23 cur=sz++; 24 st[cur].len=st[last].len+1; 25 int p; 26 for(p=last;p!=-1&&st[p].next[c]==0;p=st[p].link){ 27 st[p].next[c]=cur; 28 } 29 if(p==-1) 30 st[cur].link=0; 31 else{ 32 int q=st[p].next[c]; 33 if(st[q].len==st[p].len+1) 34 st[cur].link=q; 35 else{ 36 int clone=sz++; 37 st[clone].len=st[p].len+1; 38 st[clone].link=st[q].link; 39 for(int i=0;i<26;i++) 40 st[clone].next[i]=st[q].next[i]; 41 for(;p!=-1&&st[p].next[c]==q;p=st[p].link) 42 st[p].next[c]=clone; 43 st[cur].link=st[q].link=clone; 44 } 45 } 46 last=cur; 47 } 48 49 int main(){ 50 scanf("%d%d",&N,&Q); 51 init(); 52 for(int i=1;i<=N;i++){ 53 scanf("%s",s); 54 S[i]=(string)s; 55 n=strlen(s); 56 for(int j=0;j<n;j++){ 57 build_sam(s[j]-'a'); 58 } 59 last=0; 60 } 61 62 for(int i=1;i<=N;i++){ 63 int u=0; 64 for(int j=0;j<S[i].length();j++){ 65 u=st[u].next[S[i][j]-'a']; 66 int p=u; 67 while(p!=-1&&st[p].las!=i){ 68 st[p].ocu++; 69 st[p].las=i; 70 p=st[p].link; 71 } 72 } 73 } 74 75 for(int q=1;q<=Q;q++){ 76 scanf("%s",s); 77 n=strlen(s); 78 int u=0,flag=1; 79 for(int i=0;i<n;i++){ 80 if(st[u].next[s[i]-'a']==0){ 81 flag=0; 82 break; 83 } 84 u=st[u].next[s[i]-'a']; 85 } 86 if(!flag){ 87 printf("0 "); 88 }else 89 printf("%d ",st[u].ocu); 90 } 91 92 return 0; 93 }