CF585F Digits of Number Pi 题解
题意
- 给定长度为 的数字串 和长度为 的不含前导零的数字串 。
- 求存在长度至少为 的子串是 的子串的数字串 的数量。
- ,,答案对 取模。
题解
把 所有长度为 的子串拿出来建 AC 自动机,然后数位 dp 即可。
设 表示考虑到第 位,在 AC 自动机的 节点,是否 有上界限制时的方案数,预处理出 为第 位是否 有上界限制时的方案数。
初始时 。
枚举下一位的数字 ,设 为 AC 自动机中 节点的第 个儿子,设限制数字为 。
- 任意时刻有 ;
- 若 ,则 ;
- 若 ,则 ;
最后用乘法原理将每种方案的 相乘即可,时间复杂度 。
代码
const int N = 1e3 + 7, D = 53, K = 11;
int n, d, trie[N*D][K], ed[N*D], fail[N*D], tot = 1;
char s[N], a[D], b[D];
modint p[N][2], f[D][N*D][2];
inline void build() {
int m = d / 2;
for (int i = 1; i + m - 1 <= n; i++) {
int p = 1;
for (int j = i, k = 1; k <= m; j++, k++) {
int c = s[j] - '0';
if (!trie[p][c]) trie[p][c] = ++tot;
p = trie[p][c];
}
ed[p] = 1;
}
queue< int > q;
for (int i = 0; i < 10; i++)
if (trie[1][i]) fail[trie[1][i]] = 1, q.push(trie[1][i]);
else trie[1][i] = 1;
while (q.size()) {
int x = q.front();
q.pop();
for (int i = 0; i < 10; i++)
if (trie[x][i]) fail[trie[x][i]] = trie[fail[x]][i], q.push(trie[x][i]);
else trie[x][i] = trie[fail[x]][i];
}
}
inline modint calc(char *t) {
p[d+1][0] = p[d+1][1] = 1;
for (int i = d; i; i--) p[i][0] = p[i+1][0] * 10, p[i][1] = (t[i] - '0') * p[i+1][0] + p[i+1][1];
modint ans = 0;
for (int i = 1; i <= d; i++)
for (int j = 1; j <= tot; j++)
for (int k = 0; k < 2; k++)
f[i][j][k] = 0;
f[0][1][1] = 1;
for (int i = 0; i < d; i++)
for (int j = 1; j <= tot; j++)
if (!ed[j])
for (int k = 0; k < 10; k++) {
int o = trie[j][k];
f[i+1][o][0] += f[i][j][0];
if (k < t[i+1] - '0') f[i+1][o][0] += f[i][j][1];
if (k == t[i+1] - '0') f[i+1][o][1] += f[i][j][1];
}
for (int i = 1; i <= d; i++)
for (int j = 1; j <= tot; j++)
if (ed[j]) ans += f[i][j][0] * p[i+1][0] + f[i][j][1] * p[i+1][1];
return ans;
}
int main() {
rds(s, n), rds(a, d), rds(b, d), build();
int k = d;
while (a[k] == '0') a[k--] = '9';
--a[k];
print(calc(b) - calc(a));
return 0;
}
评论
暂无已公开评论。