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;
}