Problem Jong Hyok and String
题目大意
给你n个字符串,有q个询问。
定义set(s)={(i,j)} 表示 s在第i个字符串中出现,且末尾位置为j。
对于一个询问,求set(Qi)=set(t) ,t的数量。
(n,q<=10^5 , 字符串总长<=10^5)
解题分析
直接将n个串塞进一个后缀自动机里面。
对于一个询问串qi,找到其在后缀自动机中出现的位置j。
则答案为len[j] - len[fail[j]] 。 (具体为什么还需要好好斟酌一下)
参考程序
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 6 #define V 100008 7 int ans[V]; 8 struct sam{ 9 int nt[V*2][26],f[V*2],a[V*2],rig[V*2]; 10 int last,sum,len; 11 int p,q,np,nq; 12 13 void clear(){ 14 memset(f,-1,sizeof(f)); 15 memset(a,0,sizeof(a)); 16 memset(nt,-1,sizeof(nt)); 17 last = sum = len=0; 18 } 19 void insert(int ch){ 20 len++; 21 if (~nt[last][ch] && a[nt[last][ch]]==len){ 22 last=nt[last][ch]; return; 23 } 24 p=last; last=np=++sum; a[np]=a[p]+1; rig[np]=1; 25 for (;~p && !~nt[p][ch];p=f[p]) nt[p][ch]=np; 26 if (p==-1) f[np]=0; 27 else 28 { 29 q=nt[p][ch]; 30 if (a[q]==a[p]+1) f[np]=q; 31 else 32 { 33 nq=++sum; a[nq]=a[p]+1; 34 memcpy(nt[nq],nt[q],sizeof(nt[q])); 35 f[nq]=f[q]; 36 f[q]=f[np]=nq; 37 for (;~p && nt[p][ch]==q;p=f[p]) nt[p][ch]=nq; 38 } 39 } 40 } 41 int work(char *s,int l){ 42 int now=0; 43 for (int i=1;i<=l;i++){ 44 if (nt[now][s[i]-'a']==-1) return 0; 45 now=nt[now][s[i]-'a']; 46 } 47 return a[now]-a[f[now]]; 48 } 49 }sam; 50 51 char str[V]; 52 void work(){ 53 sam.clear(); 54 int n,m; 55 scanf("%d %d",&n,&m); 56 for (int i=1;i<=n;i++){ 57 sam.len=sam.last=0; 58 scanf("%s",str+1); 59 int len=strlen(str+1); 60 for (int j=1;j<=len;j++) sam.insert(str[j]-'a'); 61 } 62 for (int i=1;i<=m;i++){ 63 scanf("%s",str+1); 64 int len=strlen(str+1); 65 printf("%d ",sam.work(str,len)); 66 } 67 } 68 69 int main(){ 70 int T; 71 scanf("%d",&T); 72 for (int t=1;t<=T;t++){ 73 printf("Case #%d: ",t ); 74 work(); 75 } 76 return 0; 77 }