HIHOcoder1465 后缀自动机五·重复旋律8

Posted dreagonm

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HIHOcoder1465 后缀自动机五·重复旋律8相关的知识,希望对你有一定的参考价值。

思路

后缀自动机求最长循环串
首先有一个常用的处理技巧,将串复制一遍,长度大于n的子串中就包含了一组循环子串
然后是后缀自动机如何处理最长公共子串的问题
维护两个变量,u和l,u代表当前位置的最长公共子串在哪个状态中,l代表当前位置的最长公共子串的长度
然后如果当前位置有向T[i+1]转移的路径,则转移,u=trans[u][T[i]],l=l+1
如果当前位置没有转移路径,则沿suflink回跳到有转移路径的状态,如果跳到初始状态仍然没有满足条件的节点,就变成初始条件即可
注意两个地方,第一个是一个状态可能被多次统计,需要标记一下,第二个是如果l>lent,有可能=lent的状态在前面,且出现次数更多,所以需要沿suflink跳到第一个maxlen>=lent的位置
不要用memset,会T

代码

#include <queue>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define int long long
using namespace std;
const int MAXN  = 1001000*2;
int maxlen[MAXN],endpos[MAXN],suflink[MAXN],trans[MAXN][26],cnt,vis[MAXN],in[MAXN],n,ispre[MAXN],lens,lent,ans;
char s[MAXN],t[MAXN];
int new_state(int _maxlen,int *_trans,int _suflink){
    ++cnt;
    maxlen[cnt]=_maxlen;
    if(_trans)
        for(int i=0;i<26;i++)
            trans[cnt][i]=_trans[i];
    suflink[cnt]=_suflink;
    return cnt;
}
int add_len(int u,int c){
    int z=new_state(maxlen[u]+1,NULL,0);
    ispre[z]=1;
    while(u&&(!trans[u][c])){
        trans[u][c]=z;
        u=suflink[u];
    }
    if(!u){
        suflink[z]=1;
        return z;
    }
    int v=trans[u][c];
    if(maxlen[v]==maxlen[u]+1){
        suflink[z]=v;
        return z;
    }
    int y=new_state(maxlen[u]+1,trans[v],suflink[v]);
    suflink[v]=suflink[z]=y;
    while(u&&trans[u][c]==v){
        trans[u][c]=y;
        u=suflink[u];
    }
    return z;
}
int q[MAXN*3],head=1,tail=0;
void topu(void){
    head=1,tail=0;
    for(int i=1;i<=cnt;i++)
        if(suflink[i]>=1)
            in[suflink[i]]++;
    for(int i=1;i<=cnt;i++)
        if(!in[i])
            q[++tail]=i;
    while(head<=tail){
        int x=q[head];
        head++;
        endpos[x]+=ispre[x];
        endpos[suflink[x]]+=endpos[x];
        in[suflink[x]]--;
        if(!in[suflink[x]])
            q[++tail]=suflink[x];
    }
}
void work(void){
    ans=0;
    for(int i=1;i<=cnt;i++)
        vis[i]=false;
    int u=1,l=0;
    for(int i=1;i<=lent*2;i++){
        while(u!=1&&(!trans[u][t[i]-'a'])){
            u=suflink[u],l=maxlen[u];
        }
        if(trans[u][t[i]-'a']){
            u=trans[u][t[i]-'a'];
            l=l+1;
        }
        else{
            u=1;
            l=0;
        }
        if(l>lent){
            while(maxlen[suflink[u]]>=lent)
                u=suflink[u],l=maxlen[u];
        }
        if(l>=lent&&!vis[u]){
            vis[u]=true;
            ans+=endpos[u];
        }
    }
}
signed main(){
    scanf("%s",s+1);
    lens=strlen(s+1);
    int pre=1;
    cnt=1;
    for(int i=1;i<=lens;i++)
        pre=add_len(pre,s[i]-'a');
    topu();
    scanf("%lld",&n);
    for(int i=1;i<=n;i++){
        scanf("%s",t+1);
        lent=strlen(t+1);
        for(int j=1;j<=lent;j++){
            t[j+lent]=t[j];
        }
        work();
        printf("%lld
",ans);       
    }
    return 0;
}

以上是关于HIHOcoder1465 后缀自动机五·重复旋律8的主要内容,如果未能解决你的问题,请参考以下文章

hihocoder #1465 : 后缀自动机五·重复旋律8

hihocoder 1465 循环串匹配问题(后缀自动机)

hihocoder 后缀自动机五·重复旋律8 求循环同构串出现的次数

[后缀自动机] hihoCoder 1145

hihoCoder #1457 : 后缀自动机四·重复旋律7(后缀自动机 + 拓扑排序)

后缀自动机专题(hihocoder)