hiho# 1465 重复旋律8 循环串计数 后缀自动机
题意:给出一个母串,再给出n个串,问对于每个串,母串中有几个子串是可以通过循环变化得到这个串。
思路:对母串建SAM,求出$right$集。
把匹配串复制一遍,和母串进行匹配,当匹配长度大于等于$siz$时,将当时的$p$跳到最远的$len$还大于$siz$的父串(不停的往父亲跳),答案加上$right$,然后标记一下,如果标记过的就不加。(因为此时这个p是唯一的,不会被重复计算)
#include<bits/stdc++.h> #define clr(a,b) memset(a,b,sizeof(a)) using namespace std; typedef long long ll; const int inf=0x3f3f3f3f; const ll mod=1e9+7; const int maxn=200010; char s[maxn]; int len[maxn<<1],ch[maxn<<1][27],fa[maxn<<1],tot=1,root=1,last=1,siz,r[maxn<<1],vis[maxn<<1]; int a[maxn<<1],c[maxn<<1],ans[maxn<<1]; ll dp[maxn<<1]; void extend(int x){ int now=++tot,pre=last; r[now]=1; last=now,len[now]=len[pre]+1; while( pre && !ch[pre][x]){ ch[pre][x]=now; pre=fa[pre]; } if(!pre)fa[now]=root; else{ int q = ch[pre][x]; if(len[q]==len[pre]+1)fa[now]=q; else { int nows=++tot; memcpy(ch[nows],ch[q],sizeof(ch[q])); len[nows]=len[pre]+1; fa[nows]=fa[q]; fa[q]=fa[now]=nows; while(pre&&ch[pre][x]==q){ ch[pre][x]=nows; pre=fa[pre]; } } } } void topSort(){ for(int i=1;i<=tot;i++)c[len[i]]++; for(int i=1;i<=tot;i++)c[i]+=c[i-1]; for(int i=tot;i>0;i--)a[c[len[i]]--]=i; for(int i=tot;i>0;i--)r[fa[a[i]]]+=r[a[i]]; } int cal(int p,int inx){ while(fa[p]&&len[fa[p]]>=siz)p=fa[p]; return vis[p]==inx?0:(vis[p]=inx,r[p]); } int main(){ scanf("%s",s); siz=strlen(s); for(int i=0;i<siz;i++){ int p=s[i]-'a'; extend(p); } topSort(); int n; cin>>n; int index=1; while(n--){ scanf("%s",s); siz=strlen(s); for(int i=0;i<siz;i++) { s[i+siz]=s[i]; } int cur=1,maxx=0; ll ans=0; for(int i=0;i<(siz<<1);i++) { int p=s[i]-'a'; if(ch[cur][p]){ maxx++; cur=ch[cur][p]; }else{ while(cur&&ch[cur][p]==0)cur=fa[cur]; if(cur){ maxx=len[cur]+1; cur=ch[cur][p]; }else{ maxx=0; cur=1; } } if(maxx>=siz)ans+=cal(cur,index); } index++; printf("%lld\n",ans); } }
——愿为泰山而不骄
qq850874665~~