http://hihocoder.com/problemset/problem/1457
val[i] 表示状态i所表示的所有字符串的十进制之和
ans= ∑ val[i]
在后缀自动机上,从起始状态走任意一条路径到达任意一个状态,这条路径上的字符就是到达的状态的字符串之一
所以利用拓扑排序,记录从起始状态 走到这个状态的 路径数,即这个状态的字符串个数 sum
若后缀自动机上有边u-->v,加的是数字m,sum[v]+=sum[u],val[v]+=val[u]*10+sum[u]*m
至于多个串,中间加特殊字符,拓扑排序的时候不走特殊字符边即可
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int mod=1e9+7;
#define N 2000001
int tot=1,ch[N<<2][11];
int fa[N<<1],len[N<<1];
int dep[N<<1];
int last=1,p,q,np,nq;
char s[N];
int v[N<<1];
int sa[N<<1];
int sum[N<<1],val[N<<1];
void extend(int c)
{
len[np=++tot]=len[last]+1;
dep[np]=dep[last]+1;
for(p=last;p && !ch[p][c];p=fa[p]) ch[p][c]=np;
if(!p) fa[np]=1;
else
{
q=ch[p][c];
if(len[q]==len[p]+1) fa[np]=q;
else
{
nq=++tot;
fa[nq]=fa[q];
memcpy(ch[nq],ch[q],sizeof(ch[nq]));
fa[q]=fa[np]=nq;
len[nq]=len[p]+1;
dep[nq]=dep[p]+1;
for(;ch[p][c]==q;p=fa[p]) ch[p][c]=nq;
}
}
last=np;
}
void ADD(int &x,int y)
{
x+=y;
x-=x>=mod ? mod : 0;
}
int main()
{
int n;
scanf("%d",&n);
int L;
while(n--)
{
scanf("%s",s+1);
L=strlen(s+1);
for(int i=1;i<=L;++i) extend(s[i]-'0');
if(n) extend(10);
}
for(int i=1;i<=tot;++i) v[dep[i]]++;
for(int i=1;i<=tot;++i) v[i]+=v[i-1];
for(int i=1;i<=tot;++i) sa[v[dep[i]]--]=i;
sum[1]=1;
int x;
for(int i=1;i<tot;++i)
{
x=sa[i];
for(int j=0;j<10;++j)
if(ch[x][j])
{
ADD(sum[ch[x][j]],sum[x]);
ADD(val[ch[x][j]],(1LL*val[x]*10+1LL*j*sum[x])%mod);
}
}
int ans=0;
for(int i=1;i<=tot;++i) ADD(ans,val[i]);
printf("%d",ans);
}
时间限制:15000ms
单点时限:3000ms
内存限制:512MB
描述
小Hi平时的一大兴趣爱好就是演奏钢琴。我们知道一段音乐旋律可以被表示为一段数构成的数列。
神奇的是小Hi发现了一部名字叫《十进制进行曲大全》的作品集,顾名思义,这部作品集里有许多作品,但是所有的作品有一个共同特征:只用了十个音符,所有的音符都表示成0-9的数字。
现在小Hi想知道这部作品中所有不同的旋律的“和”(也就是把串看成数字,在十进制下的求和,允许有前导0)。答案有可能很大,我们需要对(10^9 + 7)取摸。
输入
第一行,一个整数N,表示有N部作品。
接下来N行,每行包含一个由数字0-9构成的字符串S。
所有字符串长度和不超过 1000000。
输出
共一行,一个整数,表示答案 mod (10^9 + 7)。
- 样例输入
-
2 101 09
- 样例输出
-
131
来源:oschina
链接:https://my.oschina.net/u/4411425/blog/3986077