描述
小Hi平时的一大兴趣爱好就是演奏钢琴。我们知道一段音乐旋律可以被表示为一段数构成的数列。
小Hi发现旋律可以循环,每次把一段旋律里面最前面一个音换到最后面就成为了原旋律的“循环相似旋律”,还可以对“循环相似旋律”进行相同的变换能继续得到原串的“循环相似旋律”。
小Hi对此产生了浓厚的兴趣,他有若干段旋律,和一部音乐作品。对于每一段旋律,他想知道有多少在音乐作品中的子串(重复便多次计)和该旋律是“循环相似旋律”。
输入
第一行,一个由小写字母构成的字符串S,表示一部音乐作品。字符串S长度不超过100000。
第二行,一个整数N,表示有N段旋律。接下来N行,每行包含一个由小写字母构成的字符串str,表示一段旋律。所有旋律的长度和不超过 100000。
输出
输出共N行,每行一个整数,表示答案。
题解:
复制模式串,以每一个字符作为后缀去匹配文本串,如果匹配长度>=len的话,进行累加;
可能会出现重复匹配的情况,应该打上标记
参考代码:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int INF=0x3f3f3f3f; const int maxn=2e6+10; char s[maxn],str[maxn]; int m,mlen,now,use[maxn]; ll ans; namespace SAM { int last,cnt,fa[maxn<<1],l[maxn<<1],nxt[maxn<<1][26]; int c[maxn<<1],rk[maxn<<1],sum[maxn<<1]; void Init() { last=cnt=1; memset(sum,0,sizeof(sum)); memset(use,0,sizeof(use)); memset(nxt[1],0,sizeof(nxt[1])); fa[1]=l[1]=0; } int NewNode() { cnt++; memset(nxt[cnt],0,sizeof(nxt[cnt])); fa[cnt]=l[cnt]=0; return cnt; } void Add(int ch) { int p=last,np=NewNode(); last=np; l[np]=l[p]+1; while(p&&!nxt[p][ch]) nxt[p][ch]=np,p=fa[p]; if(!p) fa[np]=1; else { int q=nxt[p][ch]; if(l[q]==l[p]+1) fa[np]=q; else { int nq=NewNode(); memcpy(nxt[nq],nxt[q],sizeof(nxt[q])); fa[nq]=fa[q]; l[nq]=l[p]+1; fa[np]=fa[q]=nq; while(nxt[p][ch]==q) nxt[p][ch]=nq,p=fa[p]; } } } void Build() { for(int i=1,len=strlen(s+1);i<=len;++i) sum[cnt+1]=1,Add(s[i]-'a'); for(int i=1;i<=cnt;++i) c[l[i]]++; for(int i=1;i<=cnt;++i) c[i]+=c[i-1]; for(int i=1;i<=cnt;++i) rk[c[l[i]]--]=i; for(int i=cnt;i;--i) sum[fa[rk[i]]]+=sum[rk[i]]; } void Find(int c,int n,int ti) { while(now&&!nxt[now][c]) now=fa[now],mlen=l[now]; if(!now) now=1,mlen=0; else now=nxt[now][c],mlen++; if(mlen>n) { while(l[fa[now]]>=n) { now=fa[now]; mlen=l[now]; } } if(mlen>=n&&use[now]!=ti) { use[now]=ti; ans+=1ll*sum[now]; } } } using namespace SAM; int main() { scanf("%s%d",s+1,&m); Init();Build(); for(int t=1;t<=m;++t) { scanf("%s",str+1); int n=strlen(str+1); for(int i=1;i<n;++i) str[n+i]=str[i]; int l=2*n-1; now=1;ans=0;mlen=0; for(int i=1;i<=l;++i) Find(str[i]-'a',n,t); printf("%lld\n",ans); } return 0; }