codeforces 235C. Cyclical Quest(后缀自动机)
解题思路:
既然是询问循环字符串出现次数,那么第一步当然是要倍长。
注意这里的贡献最好在广义后缀自动机中跑一遍匹配。
注意一定要一直控制其长度否则会出现前段失配现象导致算了不该算的。
代码:
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 typedef long long lnt; 5 struct sant{ 6 int tranc[26]; 7 int len; 8 int pre; 9 }s[2000000]; 10 struct pnt{ 11 lnt wgt; 12 int vis; 13 }p[2000000]; 14 struct ent{ 15 int twd; 16 int lst; 17 }e[2000000]; 18 int cnt; 19 int fin; 20 int siz; 21 int n,Q; 22 int has[2000000]; 23 int topo[2000000]; 24 char tmp[2000000]; 25 void Insert(int c) 26 { 27 int nwp,nwq,lsp,lsq; 28 nwp=++siz; 29 s[nwp].len=s[fin].len+1; 30 p[nwp].wgt=1; 31 for(lsp=fin;lsp&&!s[lsp].tranc[c];lsp=s[lsp].pre) 32 s[lsp].tranc[c]=nwp; 33 if(!lsp) 34 s[nwp].pre=1; 35 else{ 36 lsq=s[lsp].tranc[c]; 37 if(s[lsq].len==s[lsp].len+1) 38 s[nwp].pre=lsq; 39 else{ 40 nwq=++siz; 41 s[nwq]=s[lsq]; 42 s[nwq].len=s[lsp].len+1; 43 s[lsq].pre=s[nwp].pre=nwq; 44 while(s[lsp].tranc[c]==lsq) 45 { 46 s[lsp].tranc[c]=nwq; 47 lsp=s[lsp].pre; 48 } 49 } 50 } 51 fin=nwp; 52 return ; 53 } 54 int main() 55 { 56 fin=++siz; 57 scanf("%s",tmp+1); 58 int len=strlen(tmp+1); 59 for(int i=1;i<=len;i++) 60 Insert(tmp[i]-'a'); 61 for(int i=1;i<=siz;i++) 62 has[s[i].len]++; 63 for(int i=1;i<=len;i++) 64 has[i]+=has[i-1]; 65 for(int i=1;i<=siz;i++) 66 topo[has[s[i].len]--]=i; 67 for(int i=siz;i;i--) 68 { 69 int x=topo[i]; 70 p[s[x].pre].wgt+=p[x].wgt; 71 } 72 scanf("%d",&Q); 73 while(Q--) 74 { 75 scanf("%s",tmp); 76 len=strlen(tmp); 77 int ln=len<<1; 78 lnt ans=0; 79 int root=1,l=0; 80 for(int j=0;j<ln;j++) 81 { 82 int i=j%len; 83 int c=tmp[i]-'a'; 84 while(root&&!s[root].tranc[c]) 85 root=s[root].pre,l=s[root].len; 86 root=s[root].tranc[c]; 87 if(!root) 88 root=1,l=0; 89 else{ 90 l++; 91 while(s[s[root].pre].len>=len&&s[root].pre) 92 root=s[root].pre,l=s[root].len; 93 if(p[root].vis!=Q+1&&l>=len) 94 { 95 ans+=p[root].wgt; 96 p[root].vis=Q+1; 97 } 98 } 99 } 100 printf("%I64d\n",ans); 101 } 102 return 0; 103 }