hiho一下第130周 后缀自动机二·重复旋律7

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

时间限制: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 <cstring>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <time.h>
#include <string>
#include <map>
#include <stack>
#include <vector>
#include <set>
#include <queue>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int N=2e6+100;
const int M=1e6+5;
const long long MOD = 1000000007LL;
int tot,slink[2*N],trans[2*N][26],minlen[2*N],maxlen[2*N],edpts[2*N];
string str;
int n;
int containPrefix[N],ind[N],ans[2*N+10],cnt[N*2];
ll sum[N*2],sz_valid[N*2];
int newstate(int _maxlen,int _minlen,int* _trans,int _slink) {
    maxlen[++tot]=_maxlen;
    minlen[tot]=_minlen;
    slink[tot]=_slink;
    if(_trans)
        for(int i=0; i<11; i++)
            trans[tot][i]=_trans[i];
    return tot;
}
int add_char(char ch,int u) {
    int c=ch-'0',v=u;
    int z=newstate(maxlen[u]+1,-1,NULL,0);
    containPrefix[z]=1;
    while(v&&!trans[v][c]) {
        trans[v][c]=z;
        v=slink[v];
    }
    if(!v) {
        minlen[z]=1;
        slink[z]=1;
        ind[0]++;
        return z;
    }
    int x=trans[v][c];
    if(maxlen[v]+1==maxlen[x]) {
        slink[z]=x;
        minlen[z]=maxlen[x]+1;
        ind[x]++;
        return z;
    }
    int y=newstate(maxlen[v]+1,-1,trans[x],slink[x]);
    slink[z]=slink[x]=y;
    ind[y]+=2;
    minlen[x]=minlen[z]=maxlen[y]+1;
    while(v&&trans[v][c]==x) {
        trans[v][c]=y;
        v=slink[v];
    }
    minlen[y]=maxlen[slink[y]]+1;
    return z;
}
void init_dag() {
    for ( int i = 0; i <=tot; i++ ) {
        for ( int j = 0; j < 11; j++ ) {
            if ( trans[i][j] > 0 ) {
                cnt[trans[i][j]] ++;
            }
        }
    }
}

void topsort(){
    queue<int>q;
    for ( int i = 1; i <=tot; i++ ) {
        if ( cnt[i] == 0 ) {
            q.push(i);
            sz_valid[i] = 1;
            sum[i] = 0;
        }
    }
    while(!q.empty()){
        int i=q.front();
        q.pop();
        for ( int k = 0; k < 11; k++ ) {
            if ( trans[i][k] >0 ) {
                int j = trans[i][k];
                if(k < 10) {
                    sz_valid[j] += sz_valid[i];
                    sz_valid[j] %= MOD;
                    sum[j] += sum[i] * 10 + k * sz_valid[i];
                    sum[j] %= MOD;
                }
                cnt[j] --;
                if(cnt[j] == 0) q.push(j);
            }
        }
    }
}
int main() {
    cin>>n;
    cin>>str;
    for(int i=1;i<n;i++){
        string ss;
        cin>>ss;
        str=str+":"+ss;
    }
    int pre=newstate(0,0,NULL,-1);;
    tot=1;
    int len=str.length();
    for(int i=0; i<len; i++) {
        pre=add_char(str[i],pre);
    }
    init_dag();
    topsort();
    ll ans=0;
    for ( int i = 1; i <=tot; i++ ) {
        ans += sum[i];
        ans %= MOD;
    }
    cout << ans << endl;
    return 0;
}

 

posted @ 2017-01-24 16:51  贱人方  阅读(189)  评论(0编辑  收藏  举报