题目概要:
给定一个模式串 (S),然后给了 (n) 个字符串,求这 (n) 个串的循环同构在 (S) 中出现次数。
循环同构:取从左开始任意长度子串置于末尾。
每次把一段旋律里面最前面一个音换到最后面就成为了原旋律的“循环相似旋律”,还可以对“循环相似旋律”进行相同的变换能继续得到原串的“循环相似旋律”。
思路
对循环同构的处理我们很容易想到可以把相同的子串接到末尾,这样 (T[i-n+1,i])就是T的同构。
求某个串在模式串中出现次数不难想到ac自动机,但是由于存在循环同构的原因,复杂度最坏会达到 (O(n^2))。
我们知道对于 (SAM) 中每个状态,(endpos) 就是这个状态中的子串出现的次数。
于是,我们先构造 (S) 的 (SAM),并维护两个状态。(u),以 (T[i])为结尾的最长公共前缀所属状态,(l) ,最长公共前缀的长度。初始时(u=1,l=0)。
假设我们已知(T[i-1]) 的(u,l) ,如果(trans[u][T[i]]!=0) ,那么直接令(u'=trans[u][T[i]],l'=l+1) 。
如果 (trans[u][T[i]]) 不存在,我们沿着(suffix-path(u o S))找到存在的状态 (v),令 (u=trans[v][T[i]],l=maxlen[v]+1) 。
若始终不存在这样的状态,说明 (T[i]) 在 (S) 中不存在,重新初始化 (u=1,l=0)。
如果 (l geq n),说明 (lcp)中含有同构,但由于同构只是 (lcp) 的后缀,此时的状态并非我们所求的状态。
我们继续沿着后缀链接找到最后一个满足 (maxlen[v]>=n) 的状态,此时的 (endpos[v]) 即同构串出现的次数。
最后,(T)的同构可能存在重复的情况,比如 (aa) 的同构只有 (aa) ,所以我们标记每次的最终状态(v) ,解决重复的问题。
代码
//#pragma GCC optimize(2)
//#pragma GCC optimize(3, "Ofast", "inline")
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
const int N=1e6+5;
const ll mod=1e9+7;
const double eps=1e-5;
//const double pi=acos(-1);
#define ls p<<1
#define rs p<<1|1
int maxlen[N<<1],trans[N<<1][26],link[N<<1],tot=1,last=1;
int siz[N<<1],vis[N<<1],deg[N<<1];
inline void add(int id)
{
int cur=++tot,p;
siz[cur]++;
maxlen[cur]=maxlen[last]+1;
for(p=last;p&&!trans[p][id];p=link[p]) trans[p][id]=cur;
if(!p) link[cur]=1;
else
{
int x=trans[p][id];
if(maxlen[x]==maxlen[p]+1) link[cur]=x;
else
{
int y=++tot;
maxlen[y]=maxlen[p]+1;
for(int i=0;i<26;i++) trans[y][i]=trans[x][i];
link[y]=link[x];
for(;p&&trans[p][id]==x;p=link[p]) trans[p][id]=y;
link[cur]=link[x]=y;
}
}
last=cur;
}
void calc()
{
for(int i=1;i<=tot;i++) deg[link[i]]++;
queue<int>q;
for(int i=1;i<=tot;i++)
if(!deg[i]) q.push(i);
while(!q.empty())
{
int u=q.front();q.pop();
siz[link[u]]+=siz[u];
if(--deg[link[u]]==0) q.push(link[u]);
}
}
int main() {
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
#endif
ios::sync_with_stdio(false);
cin.tie(0);
string s;
cin>>s;
for(auto v:s) add(v-'a');
calc();
int _;
cin>>_;
while(_--)
{
cin>>s;
int n=s.size();
for(int i=0;i<n-1;i++) s+=s[i];
int ans=0;
int u=1,l=0;
for(auto c:s)
{
int x=c-'a';
while(u!=1&&!trans[u][x])
u=link[u],l=maxlen[u];
if(trans[u][x])
u=trans[u][x],l++;
else u=1,l=0;
if(l>=n)
{
while(maxlen[link[u]]>=n)
u=link[u],l=maxlen[u];
}
if(l>=n&&vis[u]!=_+1)
vis[u]=1+_,ans+=siz[u];
}
printf("%d
",ans);
}
return 0;
}