2012 Asia Tianjin Regional Contest - str2int

  煎熬的一个晚上。
  最后还是忍着,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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值