zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    显示器面板参数
    解决SQL Server 2008安装时提示:重新启动计算机 失败
    SQL Server 的 TSQL 语句的性能评估方法
    判断字母大小写
    linux发展史简介
    下载route命令源码
    TCP糊涂窗口综合症
    QT显示中文
    TCP四个定时器 之 TCP坚持定时器
    android 去ListView滑动阴影
  • 原文地址:https://www.cnblogs.com/dreagonm/p/10474458.html
Copyright © 2011-2022 走看看