题目大意
给若干个询问串,询问他以及他的循环同构串在原串中出现了多少次
题解
显然如果不包含循环同构的条件只要在sam上跑一遍,然后找到minlen>=串长的parent树上最高的节点就行了,答案就是这个节点的right集合的大小。对于循环同构的话,只要把串复制一份接在后面,然后统计n次即可。注意走到了同一个节点只能算一次。
1 #include <bits/stdc++.h> 2 #define ll long long 3 #define inf 0x6fffffff 4 #define N 1000086 5 using namespace std; 6 int read(){ 7 int x=0,f=1;char ch=getchar(); 8 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 9 while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} 10 return x*f; 11 } 12 char s[N]; 13 struct SAM 14 { 15 int dis[2*N],son[2*N][30],fa[2*N],sum[2*N]; 16 int tmp[2*N],rk[2*N]; 17 int vis[2*N]; 18 int last,cnt,root,n; 19 void init(){last=cnt=root=1;n=strlen(s+1);} 20 int newnode(int v){dis[++cnt]=v;return cnt;} 21 void ins(int ch) 22 { 23 int p=last,np=newnode(dis[p]+1); 24 last=np;sum[np]=1; 25 for(;p&&!son[p][ch];p=fa[p])son[p][ch]=np; 26 if(!p)fa[np]=root; 27 else{ 28 int q=son[p][ch]; 29 if(dis[q]==dis[p]+1)fa[np]=q; 30 else{ 31 int nq=newnode(dis[p]+1); 32 memcpy(son[nq],son[q],sizeof(son[q])); 33 fa[nq]=fa[q]; 34 fa[q]=fa[np]=nq; 35 for(;son[p][ch]==q;p=fa[p])son[p][ch]=nq; 36 } 37 } 38 } 39 void build() 40 { 41 init(); 42 for(int i=1;i<=n;i++)ins(s[i]-'a'); 43 for(int i=1;i<=cnt;i++)tmp[dis[i]]++; 44 for(int i=1;i<=cnt;i++)tmp[i]+=tmp[i-1]; 45 for(int i=cnt;i;i--)rk[tmp[dis[i]]--]=i; 46 for(int i=cnt;i;i--)sum[fa[rk[i]]]+=sum[rk[i]]; 47 } 48 void work(int id) 49 { 50 int n=strlen(s+1); 51 int p=root,ans=0,nl=0; 52 for(int i=1;i<2*n;i++) 53 { 54 int ch=(i<=n)?s[i]-'a':s[i-n]-'a'; 55 while(p&&son[p][ch]==0){p=fa[p];nl=dis[p];} 56 if(p==0){p=root;nl=0;} 57 else{p=son[p][ch];nl++;} 58 while(fa[p]&&dis[fa[p]]>=n){p=fa[p];nl=dis[p];} 59 if(nl>=n&&(vis[p]!=id)) 60 { 61 vis[p]=id;ans+=sum[p]; 62 } 63 } 64 printf("%d ",ans); 65 } 66 }T; 67 int main() 68 { 69 scanf("%s",s+1); 70 T.build(); 71 int n=read(); 72 for(int i=1;i<=n;i++) 73 { 74 scanf("%s",s+1);T.work(i); 75 } 76 return 0; 77 }