时间限制:
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
解题思路:
有点类似于求子串的个数,所以一开始想的是记忆化搜索,类似于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; }