Description
在这个问题中,您将得到几个字符串,这些字符串只包含 “0” 到 “9” 的数字。
字符串的集合 (S) 由输入给定的 (n) 个字符串和每个字符串的所有可能的字串组成。
操作字符串很无聊,所以你决定把 (S) 中的字符串转化整数。
可以将只包含数字的字符串转化为十进制整数,例如,可以将 “101” 转化为 101,将 “01” 转化为 1,等等。
如果一个整数出现多次,则保留其中一个。你的任务是计算所有整数的和除以 2012 的余数。
多组数据,读到 EOF 结束。
Hint
- (1le nle 10^4)
- (1le sum ext{字符串长度}le 10^5)
Solution
在解决这个问题前,我们不妨考虑一下对单个串要怎么做。
子串的问题,SAM 是一个强有力的工具。首先对整个串建 SAM,然后对建出来的这个 DAG 求拓扑序,然后大力 dp。
设:(f(x), s(x)) 分别表示从初始状态到 (x),不含前导 0 的合法 的不同子串的数量,以及 所有合法路径对应的子串的数字的总和。
那么状态转移方程:
[f(y) = sumlimits_{y in ext{sons of }x} f(x) \
s(y) = sumlimits_{{delta (x, c)=y}in ext{SAM}} s(x) + f(x) imes c
]
为了避免把前导 0 计算进去,可以约定,初始状态不能走 0 边。
现在考虑如何做多串。其实也很简单:只要将所有串拼接在一起即可。在串与串之间插入一些无用字符(如 ( exttt{#}))。
然后对拼接串建 SAM。在走的时候,除了上面的前导 0 的处理,还要规定避开无用字符的转移边。
复杂度(map
版):(O(sum| ext{str_len}| imes log|Sigma|))
Code
/*
* Author : _Wallace_
* Source : https://www.cnblogs.com/-Wallace-/
* Problem : UVA 1673 LA 6387 HDU 4436 str2int
*/
#include <iostream>
#include <map>
#include <string>
using namespace std;
const int N = 2e5 + 5;
const int mod = 2012;
namespace SAM {
const int T = N << 1;
struct Node {
map<char, int> ch;
int link, len;
} t[T];
int total;
int last;
void extend(char c) {
int p = last, np = last = ++total;
t[np].len = t[p].len + 1;
for (; p && !t[p].ch.count(c); p = t[p].link)
t[p].ch[c] = np;
if (!p) {
t[np].link = 1;
} else {
int q = t[p].ch[c];
if (t[q].len == t[p].len + 1) {
t[np].link = q;
} else {
int nq = ++total;
t[nq].ch = t[q].ch, t[nq].link = t[q].link;
t[nq].len = t[p].len + 1;
t[q].link = t[np].link = nq;
while (p && t[p].ch.count(c) && t[p].ch[c] == q)
t[p].ch[c] = nq, p = t[p].link;
}
}
}
void init(string& s) {
for (register int i = 1; i <= total; i++) t[i] = Node();
last = total = 1;
for (string::iterator it = s.begin(); it != s.end(); it++) extend(*it);
}
int b[T], c[T];
void topo_sort() {
for (register int i = 1; i <= total; i++) b[i] = c[i] = 0;
for (register int i = 1; i <= total; i++) ++c[t[i].len];
for (register int i = 1; i <= total; i++) c[i] += c[i - 1];
for (register int i = 1; i <= total; i++) b[c[t[i].len]--] = i;
}
int f[T], s[T];
int calc();
};
int SAM::calc() {
for (register int i = 1; i <= total; i++) f[i] = s[i] = 0;
f[1] = 1;
for (register int i = 1; i <= total; i++) {
int x = b[i];
for (map<char, int>::iterator it = t[x].ch.begin(); it != t[x].ch.end(); it++) {
int y = it->second, c = it->first;
if (char(c) == '0' && x == 1) continue;
if (char(c) == '#') continue;
(f[y] += f[x]) %= mod;
(s[y] += s[x] * 10 + f[x] * (c - '0')) %= mod;
}
}
int ans = 0;
for (register int i = 1; i <= total; i++)
(ans += s[i]) %= mod;
return ans;
}
signed main() {
ios::sync_with_stdio(false);
int n;
while (cin >> n) {
string str = "", tmp;
while (n--) {
cin >> tmp;
str.append("#");
str.append(tmp);
}
str.erase(str.begin());
SAM::init(str);
SAM::topo_sort();
cout << SAM::calc() << endl;
}
return 0;
}