• HIHOcoder 1457 后缀自动机四·重复旋律7


    思路

    后缀自动机题目,题目本质上是要求求出所有不同的子串的和,SAM每个节点中存放的子串互不相同,所以对于每个节点的sum,可以发现是可以递推的,每个点对子节点贡献是sum[x]*10+c*sz[x],对于单个串,sz[x]就是maxlen[x]-minlen[x]+1,现在有多个串,可以用其他字符分割,然后建出SAM,注意到新的合法的sz是不能跨越两个不同的串的,SAM上的一条路径就是一个子串,所以求sz等价于统计不经过分隔符的路径条数,拓扑排序即可

    代码

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <string>
    #include <queue>
    #include <iostream>
    #define int long long
    using namespace std;
    const int MAXN = 1000100*2;
    const int MOD = 1000000007;
    int cnt,trans[MAXN][11],maxlen[MAXN],sz[MAXN],in[MAXN],suflink[MAXN],sum[MAXN],ok[MAXN],n,len=0;
    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<11;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);
        if(c==10)
            ok[z]=true;
        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[z]=suflink[v]=y;
        while(u&&trans[u][c]==v){
            trans[u][c]=y;
            u=suflink[u];
        }   
        return z;
    }
    queue<int> q;
    signed main(){
        scanf("%lld",&n);
        for(int i=1;i<=n;i++){
            scanf("%s",t+1);
            int midlen=strlen(t+1);
            if(i!=1)
                s[++len]='0'+10;
            for(int j=1;j<=midlen;j++)
                s[len+j]=t[j];
            len+=midlen;
        }
        s[len+1]='';
        // printf("%s
    %lld
    ",s+1,len);
        int pre=1;
        cnt=1;
        for(int i=1;i<=len;i++)
            pre=add_len(pre,s[i]-'0');
        // printf("cnt=%d
    ",cnt);
        for(int i=1;i<=cnt;i++){
            for(int j=0;j<11;j++)
                if(trans[i][j])
                    in[trans[i][j]]++;
        }
        for(int i=1;i<=cnt;i++)
            if(!in[i])
                q.push(i);
        sz[1]=1;
        sum[1]=0;
        while(!q.empty()){
            int x=q.front();
            q.pop();
            for(int i=0;i<11;i++){
                if(trans[x][i]){
                    if(i<10){
                        sz[trans[x][i]]=(sz[x]+sz[trans[x][i]])%MOD;
                        sum[trans[x][i]]=(sum[trans[x][i]]+sum[x]*10%MOD+i*sz[x]%MOD)%MOD;
                    }
                    in[trans[x][i]]--;
                    if(!in[trans[x][i]])
                        q.push(trans[x][i]);
                }
            }
        }
        int ans=0;
        for(int i=1;i<=cnt;i++)
            if(!ok[i])
                ans=(ans+sum[i])%MOD;
        printf("%lld
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    一个纠结的问题
    打开SQL Developer时,提示缺少快捷方式
    打开eclipse时,An error has occurred. See the log file
    bash: id : command not found
    Fatal error: Call to undefined function: mysql_connect()解决方法
    struts.xml中标签自动提示问题
    Hibernate向Oracle中添加自增字段
    linux 忘记root密码的解决办法
    ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock'
    Ctrl+Alt+Fn不能切换到字符界面
  • 原文地址:https://www.cnblogs.com/dreagonm/p/10470749.html
Copyright © 2020-2023  润新知