若干的数字串所有不同子串的和 后缀自动机

时间限制:15000ms
单点时限:3000ms
内存限制:512MB
描述

小Hi平时的一大兴趣爱好就是演奏钢琴。我们知道一段音乐旋律可以被表示为一段数构成的数列。

神奇的是小Hi发现了一部名字叫《十进制进行曲大全》的作品集,顾名思义,这部作品集里有许多作品,但是所有的作品有一个共同特征:只用了十个音符,所有的音符都表示成0-9的数字。

现在小Hi想知道这部作品中所有不同的旋律的“和”(也就是把串看成数字,在十进制下的求和,允许有前导0)。答案有可能很大,我们需要对(10^9 + 7)取摸。

解题方法提示

输入

第一行,一个整数N,表示有N部作品。

接下来N行,每行包含一个由数字0-9构成的字符串S。

所有字符串长度和不超过 1000000。

输出

共一行,一个整数,表示答案 mod (10^9 + 7)。

样例输入
2
101
09
样例输出
131

好!这道题目让我们求的是若干的数字串所有不同子串的和。

#include <iostream>
#include <string>
#include <vector>

using namespace std;

const int MAXL=1000000;
const int MAXM=MAXL*2+10;
const int NUM_ST=11;
const long long MOD = 1000000007LL;
string s;
int n = 0,len,st;
int maxlen[MAXM],minlen[MAXM],trans[MAXM][NUM_ST],slink[MAXM];
int tot[MAXM],que[MAXM];
long long sum[MAXM],sz_valid[MAXM];

int new_state(int _maxlen,int _minlen,int* _trans,int _slink) {
    maxlen[n] = _maxlen;
    minlen[n] = _minlen;
    for(int i = 0; i < NUM_ST; 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];
    }
    // case 1
    if(v==-1) {
        minlen[z] = 1;
        slink[z]  = 0;
        return z;
    }
    // case 2
    int x = trans[v][c];
    if(maxlen[v] + 1 == maxlen[x]) {
        minlen[z] = maxlen[x] + 1;
        slink[z]  = x;
        return z;
    }
    // case 3
    int y = new_state(maxlen[v] + 1, minlen[x], trans[x], 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];
    }
    return z;
}

void init_dag() {
    for ( int i = 0; i < n; i++) {
        tot[i] = 0;
        sum[i] = 0;
        sz_valid[i] = 0;
    }
    for ( int i = 0; i < n; i++ ) {
        for ( int j = 0; j < NUM_ST; j++ ) {
            if ( trans[i][j] >= 0 ) {
                tot[trans[i][j]] ++;
            }
        }
    }
}

void topo_sort() {
    int qa,qn;
    qa = qn = 0;
    for ( int i = 0; i < n; i++ ) {
        if ( tot[i] == 0 ) {
            que[qn++] = i;
            sz_valid[i] = 1;
            sum[i] = 0;
        }
    }
    for ( ; qa < qn; ) {
        int i,j;
        i = que[qa++];
        for ( int k = 0; k < NUM_ST; k++ ) {
            if ( trans[i][k] >= 0 ) {
                j = trans[i][k];
                if(k < NUM_ST-1) {
                    sz_valid[j] += sz_valid[i];
                    sz_valid[j] %= MOD;
                    sum[j] += sum[i] * 10 + k * sz_valid[i];
                    sum[j] %= MOD;
                } else {

                }
                tot[j] --;
                if(tot[j] == 0) que[qn++] = j;
            }
        }
    }
}

int main() {
    ios::sync_with_stdio(false); cin.tie(0);
    int num_strings;
    cin >> num_strings;
    cin >> s;
    for(int i = 1; i < num_strings; i++) {
        string ss; cin >> ss;
        s = s + ":" + ss;
    }
    int len = (int)s.length();
    st = new_state(0,0,NULL,-1);
    for(int i = 0; i < len; i++) {
        st = add_char(s[i],st);
    }
    init_dag();
    topo_sort();
    long long ans = 0;
    for ( int i = 0; i < n; i++ ) {
        ans += sum[i];
        ans %= MOD;
    }
    cout << ans << endl;
    return 0;
}

posted @ 2017-09-19 21:17  黑码的博客  阅读(100)  评论(0编辑  收藏  举报