若干的数字串所有不同子串的和 后缀自动机
时间限制: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;
}