Address
https://www.lydsy.com/JudgeOnline/problem.php?id=1974
Solution
看上去是一个显然的数位 dp ,但是看到
N≤1018
N
≤
10
18
的数据范围就发现不是那么容易了。
本题的思路最巨之处就在于:
将 1111111…222222…333333…44444…5555… 式的数拆成不到 9 个形如 11111111111 的数之和,并且至少要有一个 111111111111111111111111111…111( N 个 1 ) 。
又由于
11111111111111111...111
11111111111111111...111
形式的数对
P
P
取模的值随 的个数满足周期性变化,所以我们可以用一个数组
cnt[]
c
n
t
[
]
,储存:
cnt[i]
c
n
t
[
i
]
表示
111111111111111111...11111
111111111111111111...11111
(
1≤1
1
≤
1
的个数
≤N
≤
N
)形式的数有多少个。可以利用周期性预处理出。
从小到大考虑
11111111111111111...11
11111111111111111...11
形式的数,可以 dp 辣!
f[i][j][k]
f
[
i
]
[
j
]
[
k
]
表示考虑到
cnt[i]
c
n
t
[
i
]
, 使用
k
k
个 形式的数,它们之和模
P
P
的值为 的方案数
(注意
k
k
的上界是 不是
9
9
,最后我们还要加上 (
N
N
个 ))
前置公式:
n
n
种元素,每种元素有无穷多个,从中取出 个元素的不同方案数为
(n+m−1m)
(
n
+
m
−
1
m
)
。
边界:
注意到 cnt c n t 的值很大但 k k 的值很小,组合数可以预处理。
枚举使用的模 为 i i 的 的个数 h h ( ) ,就能实现转移。
答案:
这种拆分成 111111111111111111111111111111111111...111 111111111111111111111111111111111111...111 的思路真的很难想到。
Code
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define For(i, a, b) for (i = a; i <= b; i++)
#define Rof(i, a, b) for (i = a; i >= b; i--)
typedef long long ll; using namespace std;
const int N = 505, M = 1e5 + 5, E = 11, PYZ = 999911659;
int CYX, b[M], f[N][N][E], dalao, orz[N], fac[N], inv[N], otz[N][N];
ll n, cnt[N];
int qpow(int a, int b) {
int res = 1; while (b) b & 1 ? res = 1ll * res * a % PYZ : 0,
a = 1ll * a * a % PYZ, b >>= 1; return res;
}
int main() {
int i, j, k, h, rep, len, gap, ans = 0;
cin >> n >> CYX; For (i, 1, 2147483647) {
b[i] = (b[i - 1] * 10 + 1) % CYX;
if (orz[b[i]]) {rep = orz[b[i]]; len = i; break;}
orz[b[i]] = i;
}
For (i, 1, min(1ll * rep - 1, n)) cnt[b[i]]++;
gap = len - rep; if (rep <= n) For (i, rep, len - 1) {
cnt[b[i]] += (n / gap + (i % gap <= n % gap))
- ((rep - 1) / gap + (i % gap <= (rep - 1) % gap));
if (n % gap == i % gap) dalao = b[i];
}
fac[0] = 1; For (i, 1, 20) fac[i] = 1ll * fac[i - 1] * i % PYZ;
inv[20] = qpow(fac[20], PYZ - 2); Rof (i, 19, 0)
inv[i] = 1ll * inv[i + 1] * (i + 1) % PYZ;
For (i, 0, CYX - 1) {
if (!cnt[i]) {
otz[i][0] = 1; For (j, 1, 20) otz[i][j] = 0; continue;
}
otz[i][0] = 1; For (j, 1, 20) otz[i][j] = 1ll * otz[i][j - 1]
* ((cnt[i] + j - 1) % PYZ) % PYZ;
For (j, 1, 20) otz[i][j] = 1ll * otz[i][j] * inv[j] % PYZ;
}
For (i, 0, 8) f[0][0][i] = otz[0][i];
For (i, 1, CYX - 1) For (j, 0, CYX - 1) For (k, 0, 8) For (h, 0, k)
f[i][j][k] = (f[i][j][k] + 1ll * f[i - 1]
[(j - i * h % CYX + CYX) % CYX][k - h] * otz[i][h] % PYZ) % PYZ;
For (i, 0, 8) ans = (ans + f[CYX - 1][(CYX - dalao) % CYX][i]) % PYZ;
cout << ans << endl; return 0;
}