描述
小Hi平时的一大兴趣爱好就是演奏钢琴。我们知道一段音乐旋律可以被表示为一段数构成的数列。
神奇的是小Hi发现了一部名字叫《十进制进行曲大全》的作品集,顾名思义,这部作品集里有许多作品,但是所有的作品有一个共同特征:只用了十个音符,所有的音符都表示成0-9的数字。
现在小Hi想知道这部作品中所有不同的旋律的“和”(也就是把串看成数字,在十进制下的求和,允许有前导0)。答案有可能很大,我们需要对(10^9 + 7)取摸。
输入
第一行,一个整数N,表示有N部作品。
接下来N行,每行包含一个由数字0-9构成的字符串S。
所有字符串长度和不超过 1000000。
输出
共一行,一个整数,表示答案 mod (10^9 + 7)。
2 101 09样例输出
131
解题思路:
有点类似于求子串的个数,所以一开始想的是记忆化搜索,类似于dp[v] = sum(dp[u]*10+'c'-'0'),但因为包含多个串(这里在每个子串的末尾添加一个字符‘A’,然后将这些字符串合成一个字符串),向上回朔时碰到‘A’的话,此时dp[u]*10就会发生错误,导致结果远大于答案。
这里对每个节点状态的子串和进行计算,用sum[v]表示。首先对单个字符分析,若v能通过字符c转移到状态u,此时sum[u] = sum[v]*10+subnum(u)*(c-'0'),其中subnum(u)为状态u的子串个数。现在我们考虑多个字符串的情况。对于状态v的子串中包含‘A’的我们应不予考虑,所以sum[v] = sum[u]*10+noA_subnum(u)*(c-'0'),noA_subnum(u)表示不包括‘A’的子串个数。即noA_subnum(u)表示从初始状态到状态u不包含‘A’的路径条数,这里我们可以用拓扑排序来处理。
代码:
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <string>
#include <map>
#include <queue>
using namespace std;
typedef long long llt;
const int N = 1000010;
const int mod = 1e9+7;
struct state{
int len,link;
map<char,int>next;
}st[N*2];
int sz,last,indeg[N*2],cnt[N*2];
llt sum[N*2];
void sa_init()
{
sz = last = 0;
st[0].len = 0;
st[0].link = -1;
++sz;
for(int i = 0; i < N; ++i)
st[i].next.clear();
memset(indeg,0,sizeof(indeg));
memset(cnt,0,sizeof(cnt));
}
void sa_extend(char c)
{
int cur = sz++; //新添加的状态结点
st[cur].len = st[last].len+1;
int p;
for(p = last; p != -1 && !st[p].next.count(c); p = st[p].link)
st[p].next[c] = cur,indeg[cur]++;
if(p == -1)
st[cur].link = 0;
else{
int q = st[p].next[c];
if(st[p].len+1 == st[q].len)
st[cur].link = q;
else{
int clone = sz++;
st[clone].len = st[p].len+1;
st[clone].next = st[q].next;
for(auto it = st[q].next.begin(); it != st[q].next.end(); ++it){
int t = (*it).second; indeg[t]++;
}
st[clone].link = st[q].link;
for(; p != -1 && st[p].next[c] == q; p = st[p].link){
int t = st[p].next[c];
st[p].next[c] = clone;
indeg[t]--; indeg[clone]++;
}
st[q].link = st[cur].link = clone;
}
}
last = cur;
}
void bfs()
{
queue<int>q;
for(int i = 0; i < sz; ++i) if(indeg[i] == 0) q.push(i);
cnt[0] = 1;
while(!q.empty()){
int u = q.front();
q.pop();
for(auto it = st[u].next.begin(); it != st[u].next.end(); ++it){
int v = (*it).second;
char ch = (*it).first;
indeg[v]--;
if(indeg[v] == 0) q.push(v);
if(ch == 'A') continue;
cnt[v] += cnt[u];
sum[v] = (sum[v]+sum[u]*10+cnt[u]*(ch-'0'))%mod;
}
}
}
int main()
{
sa_init();
string str,s; int n;
cin >> n;
for(int i = 0; i < n; ++i) cin >> s,str += s+'A';
for(int i = 0; i < str.length(); ++i)
sa_extend(str[i]);
bfs();
llt ans = 0;
for(int i = 0; i < sz; ++i)
ans = (ans+sum[i])%mod;
printf("%lld\n",ans);
return 0;
}