把所有的字符串连接起来,中间用一个未出现的字符分隔开,题意是求这个串的所有子串(中间不含分隔符)形成的数之和。
把这个串加入SAM,对所有子串进行拓扑排序,从前往后统计。
记录到达这个节点的路径个数cnt,以及到达这个节点的总和sum。
设父节点是u,子节点是v
sum[v] = sum[u] * 10 + sum[v] + cnt[v]*j;
cnt[v] += cnt[u];
ans就是把所有的sum加起来。
注意:
1.忽略前导零
2.子串中不要含分隔符
#include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> using namespace std; const int MAXN = 100100; const int segma_size = 14; const int MOD = 2012; struct Suffix_Automaton { int F[MAXN << 1]; //fail int ant; //sum node int last; //last point int ch[MAXN << 1][segma_size]; //side int step[MAXN << 1]; //len void init() { last = ant = 1; memset(F,0,sizeof(F)); memset(ch,0,sizeof(ch)); memset(step,0,sizeof(step)); return; } void ins( int x ) { int t = ++ant, pa = last; step[t] = step[last] + 1; last = t; for( ; pa && !ch[pa][x]; pa = F[pa] ) ch[pa][x] = t; if( pa == 0 ) F[t] = 1; else if( step[pa] + 1 == step[ ch[pa][x] ] ) F[t] = ch[pa][x]; else { int nq = ++ant, q = ch[pa][x]; memcpy( ch[nq], ch[q], sizeof(ch[nq]) ); step[nq] = step[pa] + 1; F[nq] = F[q]; F[q] = F[t] = nq; for( ; pa && ch[pa][x] == q; pa = F[pa] ) ch[pa][x] = nq; } } }; int N; char str[MAXN + 20]; int strL; Suffix_Automaton SAM; int r[MAXN << 1]; int sum[MAXN << 1]; int cnt[MAXN << 1]; bool cmp( int a, int b ) { return SAM.step[a] < SAM.step[b]; } void show() { for ( int i = 0; i <= SAM.ant; ++i ) { for ( int j = 0; j < 10; ++j ) { printf( "%d ", SAM.ch[i][j] ); } puts(""); } return; } int main() { //freopen( "s.txt", "w", stdout ); while ( scanf( "%d", &N ) == 1 ) { SAM.init(); strL = 0; for ( int n = 0; n < N; ++n ) { if ( strL ) str[strL++] = '9' + 1; scanf( "%s", &str[strL] ); strL += strlen( &str[strL] ); } for ( int i = 0; i < strL; ++i ) SAM.ins( str[i] - '0' ); for ( int i = 0; i <= SAM.ant; ++i ) r[i] = i; sort( r + 1, r + 1 + SAM.ant, cmp ); memset( sum, 0, sizeof(int)*(SAM.ant+4) ); memset( cnt, 0, sizeof(int)*(SAM.ant+4) ); int ans = 0; cnt[1] = 1; for ( int i = 1; i <= SAM.ant; ++i ) { int u = r[i]; if ( i > 1 && !cnt[u] ) continue; ans = ( ans + sum[u] ) % MOD; for ( int j = 0; j < 10; ++j ) { if ( u == 1 && j == 0 ) continue; if ( !SAM.ch[u][j] ) continue; int v = SAM.ch[u][j]; sum[v] = ( sum[u] * 10 + sum[v] + cnt[u] * j ) % MOD; cnt[v] += cnt[u]; } } printf( "%d\n", ans ); } return 0; }