zoukankan      html  css  js  c++  java
  • hihocoder 1457(后缀自动机+拓扑排序)

    题意

    给定若干组由数字构成的字符串,求所有不重复子串的和(把他们看成十进制),答案mod(1e9+7)

    题解:

    类似后缀数组的做法,把字符串之间用':'连接,这里用':'是因为':'的ascii码恰好是9的下一个

    然后建立后缀自动机。

    之后把其实只要把其中的所有':'边删去,就可以进行转移了

    如果x连向了y,边权是c,那么有转移

    dp[y] += dp[x]*10 + c*sz[x]

    所以只要拓扑排序一下就好

    (写这题wa了好几次,主要是在删边建立新图的过程出了问题)

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <queue>
    using namespace std;
    typedef long long LL;
    int n = 0, len, st;
    const int maxL = 2e6 + 100;
    const int MOD = 1e9 + 7;
    int maxlen[2*maxL], minlen[2*maxL], trans[2*maxL][12], slink[2*maxL], col[2*maxL];
    LL in[2*maxL], dp[2*maxL], sz[2*maxL];
    int new_state(int _maxlen, int _minlen, int *_trans, int _slink){
        maxlen[n] = _maxlen;
        minlen[n] = _minlen;
        for(int i = 0; i < 11; i++){
            if(_trans == NULL)
                trans[n][i] = -1;
            else
                trans[n][i] = _trans[i];
        }
        slink[n] = _slink;
        return n++;
    }
    
    int add_char(char ch, int u){
        int c = ch - '0';
        int z = new_state(maxlen[u]+1, -1, NULL, -1);
        int v = u;
        while(v != -1 && trans[v][c] == -1){
            trans[v][c] = z;
            v = slink[v];
        }
        if(v == -1){
            minlen[z] = 1;
            slink[z] = 0;
            return z;
        }
        int x = trans[v][c];
        if(maxlen[v] + 1 == maxlen[x]){
            minlen[z] = maxlen[x] + 1;
            slink[z] = x;
            return z;
        }
        int y = new_state(maxlen[v] + 1, -1, trans[x], slink[x]);
        slink[y] = slink[x];
        minlen[x] = maxlen[y] + 1;
        slink[x] = y;
        minlen[z] = maxlen[y] + 1;
        slink[z] = y;
        int w = v;
        while(w != -1 && trans[w][c] == x){
            trans[w][c] = y;
            w = slink[w];
        }
        minlen[y] = maxlen[slink[y]] + 1;
        return z;
    }
    
    char str[maxL];
    queue<int> Q;
    int main()
    {
        freopen("a.txt", "r", stdin);
        int N;
        cin>>N;
        st = new_state(0, 0, NULL, -1);
        while(N--){
            cin>>str;
            int len = strlen(str);
            for(int i = 0; i < len; i++) {
                st = add_char(str[i], st);
            }
            st = add_char(':', st);
        }
        Q.push(0); col[0] = 1;
        while(!Q.empty()){
            int x = Q.front(); Q.pop();
            for(int c = 0; c < 10; c++){
                int y = trans[x][c];
                if(y == -1) continue;
                if(!col[y]) Q.push(y); col[y] = 1;
                in[y]++;
            }
        }
        Q.push(0); sz[0] = 1;
        while(!Q.empty()){
            int x = Q.front(); Q.pop();
            for(int c = 0; c < 10; c++){
                int y = trans[x][c];
                if(y == -1) continue;
                in[y]--;
                if(in[y] == 0) Q.push(y);
                (sz[y] += sz[x]) %= MOD;
                (dp[y] += dp[x]*10 + c*sz[x]) %= MOD;
            }
        }
        LL ans = 0;
        /*
        for(int i = 0; i <  n; i++){
            for(int c = 0; c < 10; c++){
                if(trans[i][c] == -1) continue;
                cout<<i<<" "<<trans[i][c]<<" "<<c<<endl;
            }
        }*/
        //for(int i = 0; i < n; i++) cout<<dp[i]<<" "; cout<<endl;
        for(int i = 0; i < n; i++) (ans += dp[i]) %= MOD;
        cout<<ans<<endl;
        return 0;
    }
  • 相关阅读:
    二叉排序树的查找和插入操作
    二叉排序树(二叉查找树)- 数据结构和算法73
    线性索引查找
    斐波那契查找(黄金分割法查找)- 数据结构和算法71
    插值查找(按比例查找)- 数据结构和算法70
    序列!序列!- 零基础入门学习Python016
    字符串:格式化
    字符串:各种奇葩的内置方法
    为duilib的MenuDemo增加消息响应,优化代码和显示效果
    为duilib的MenuDemo增加消息响应,优化代码和显示效果
  • 原文地址:https://www.cnblogs.com/Saurus/p/7101021.html
Copyright © 2011-2022 走看看