UVa 1673 str2int

Rujia紫书上的例题(参见 P392 ) , 以前一直以为CLJ是第一个将这玩意引进中国的 , 但其实早在2009年 , Rujia就将这一强有力的处理字符串的武器带给了我们。 本质上 , SAM就是DAWG的一个实例化 , 如果想对自动机有更深入的了解 , 推荐看看紫书。

此题几乎就是照着Rujia的讲解写的 , 因为代码仓库里没有这一章的代码 , 贴出来给大家参考。 唯一的不同是Rujia为了避免讨论广义后缀自动机 , 将字符串之间添加了 junk 字符来分割 , 但是这并不是必须的 , 只需要没次将 last 指针指向 Root 即可 , 这一方案第一次见到是去年浙江的省选题 , CLJ出的诸神眷顾的幻想乡

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <string>
#include <vector>
#include <deque>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <algorithm>
#include <cassert>

using namespace std;
const int modu = 2012;
const int maxn = 2e5+1e2;
const int maxnode = maxn;
const int sigmaSize = 10;

char s[maxn];

int id(char c) { return c-'0'; }

struct SAM
{
    int n , last;
    int ch[maxnode][sigmaSize] , fa[maxnode] , mx[maxnode];
    int c[maxn] , q[maxnode];
    int sum[maxn] , cnt[maxn];

    int newNode()       { mx[++n] = 0; memset(ch[n], 0, sizeof(ch[n])); return n; }
    void init(){ mx[n = last = 1] = 0; memset(ch[1], 0, sizeof(ch[1]));           }

    void extend(int x)
    {
        int p = last , np = newNode(); 
        mx[last = np] = mx[p] + 1;

        while(p && !ch[p][x]) ch[p][x] = np , p = fa[p];

        if(!p) fa[np] = 1;
        else 
        {
            int q = ch[p][x];
            if(mx[q] == mx[p]+1) fa[np] = q;
            else 
            {
                int nq = newNode();
                mx[nq] = mx[p] + 1;
                memcpy(ch[nq], ch[q], sizeof(ch[0]));
                fa[nq] = fa[q];
                fa[q] = fa[np] = nq;

                while(p && ch[p][x] == q) ch[p][x] = nq , p = fa[p];
            }
        }
    }

    void sort()
    {
        memset(c, 0, sizeof(int)*(n+1));
        for(int i=1;i<=n;i++) c[mx[i]]++;
        for(int i=1;i<=n;i++) c[i] += c[i-1];
        for(int i=1;i<=n;i++) q[c[mx[i]]--] = i;
    }

    int dp()
    {
        sort();
        memset(sum, 0, sizeof(int)*(n+1));
        memset(cnt, 0, sizeof(int)*(n+1));

        sum[1] = 0; cnt[1] = 1;
        for(int i=1 , j;i<=n;i++)
        {
            j = q[i];
            for(int k=0,t;k<sigmaSize;k++)
            {
                if(j==1 && !k) continue;
                t = ch[j][k];
                (sum[t] += cnt[j]*k + sum[j]*10) %= modu;
                (cnt[t] += cnt[j])               %= modu;
            }
        }
        int res = 0;
        for(int i=1;i<=n;i++) (res += sum[i]) %= modu;
        return res;
    }
}solver;

int n;

int main(int argc, char *argv[]) {

    while(cin>>n)
    {
        solver.init();
        while(n--)
        {
            scanf("%s" , s);
            solver.last = 1;
            for(int i=0,j=strlen(s);i<j;i++) solver.extend(id(s[i]));
        }

        cout<<solver.dp()<<endl;
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值