煎熬的一个晚上。
最后还是忍着,A了这题。
似乎已经完全没有动力了。
I’ve lost almost everything.
回到这题来吧
实际上就是要统计所有不同的字符串子串的和。
建一个SAM,每两个字符串之间插个间隔符,拓扑排序完从root顺着每条边往下走统计答案。注意一开始不能走前导零。
时间复杂度是线性的。
#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
#define cr(x) memset(x , 0 , sizeof x)
#define maxn 100007
#define maxm 250007
inline int rd() {
char c = getchar();
while (!isdigit(c)) c = getchar() ; int x = c - '0';
while (isdigit(c = getchar())) x = x * 10 + c - '0';
return x;
}
const int mod = 2012;
inline int add(int a , int b) { a += b ; if (a >= mod) a %= mod ; return a; }
inline int mul(int a , int b) { a *= b ; if (a >= mod) a %= mod ; return a; }
typedef int sam[maxm];
sam fa , sz , cnt , len , tp , sum;
int go[maxm][11] , tot , ed;
int n , ans , m;
char str[maxn];
void addc(int c , int l) {
int p = ed , np = ed = ++ tot;
len[np] = len[p] + 1;
while (p && !go[p][c]) go[p][c] = np , p = fa[p];
if (!p) {
fa[np] = 1;
return ;
}
int q = go[p][c];
if (len[q] == len[p] + 1) {
fa[np] = q;
return ;
}
int r = ++ tot;
len[r] = len[p] + 1;
memcpy(go[r] , go[q] , sizeof go[q]);
fa[r] = fa[q];
fa[q] = fa[np] = r;
while (go[p][c] == q) go[p][c] = r , p = fa[p];
}
void add_str(char*s) {
int l = strlen(s + 1);
rep (i , 1 , l) addc(s[i] - '0' , ++ m);
addc(10 , ++ m);
}
void input() {
ed = tot = 1 , m = 0;
cr(go) , cr(sz);
sz[1] = 1;
rep (i , 1 , n) {
scanf("%s" , str + 1);
add_str(str);
}
}
void tpsort() {
cr(cnt) , cr(sum);
rep (i , 1 , tot) cnt[len[i]] ++;
rep (i , 1 , m ) cnt[i] += cnt[i - 1];
per (i , tot , 1) tp[cnt[len[i]] --] = i;
rep (i , 1 , tot) {
int u = tp[i];
ans = add(ans , sum[u]);
rep (c , (i == 1) , 9) {
int v = go[u][c];
if (v) {
sz[v] = add(sz[v] , sz[u]);
sum[v] = add(sum[v] , add(mul(sum[u] , 10) , mul(sz[u] , c)));
}
}
}
}
void solve() {
ans = 0;
tpsort();
printf("%d\n" , ans);
}
int main() {
#ifndef ONLINE_JUDGE
freopen("data.txt" , "r" , stdin);
#endif
while (scanf("%d" , &n) == 1) {
input();
solve();
}
return 0;
}