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);
    }

}

 

posted @ 2019-04-07 19:09  光芒万丈小太阳  阅读(231)  评论(0编辑  收藏  举报