Description:
1<=n<=1e1000, 1 <= p <= 1e9, 1 <= k <= 1e9
题解:
题目要求:
∑ni=1∑ij=1[Cji含有的p的幂次>=k]
我们知道有库默尔定理,这是这道题的基础。
库默尔定理:
[Cji+j含有的p的幂次=i+j在p进制下的进位数
所以此题可以转换为:
∑ni=1∑nj=1[i+j<=n]∗[i+j在p进制的下的进位数]
n这么大,肯定数位dp了,但是好像很复杂。
先把n转成p进制。
设fi,j,0/1,0/1分别表示做了前i位(从低位到高位),一共进位了j次,当前第i位是否进位,以及组成的数是否<=n的前i位。
暴力转移:枚举当前位上的两个数。
随便分类讨论一波,发现贡献是等差数列,于是转移成O(1)的,细节超繁琐, 见代码。
#include <cstdio>
#include <cstring>
#define ll long long
#define fo(i, x, y) for(ll i = x; i <= y; i ++)
#define fd(i, x, y) for(ll i = x; i >= y; i --)
#define min(a, b) ((a) < (b) ? (a) : (b))
#define max(a, b) ((a) > (b) ? (a) : (b))
using namespace std;
const ll w = 4, M = 10000, mo = 1e9 + 7;
const ll ni = 5e8 + 4;
char s[10005];
struct node {
ll w, a[10005];
}n;
ll len, num[10005];
ll a[10000], p, k;
ll f[2000][2000][2][2];
ll chu(node &a, ll b) {
ll y = 0;
fd(i, a.w, 1) {
a.a[i] += y * M;
y = a.a[i] % b; a.a[i] /= b;
}
while(a.w > 1 && a.a[a.w] == 0) a.w --;
return y;
}
void Init() {
scanf("%s", s + 1); len = strlen(s + 1);
scanf("%lld %lld", &p, &k);
n.w = 0; ll v = 0;
fd(i, len, 1) {
v = (v + 1) % 4;
n.w += v == 1; num[i] = n.w;
}
fo(i, 1, len) n.a[num[i]] = n.a[num[i]] * 10 + s[i] - 48;
while(!(n.w == 1 && n.a[1] == 0))
a[++ a[0]] = chu(n, p);
}
ll s1(ll x, ll y) {
if(x > y) return 0;
x %= mo; y %= mo;
ll z = (y - x + 1) % mo;
return (2 * p - 1) % mo * z % mo - (x + y) * z % mo * ni % mo;
}
ll s2(ll x, ll y) {
if(x > y) return 0;
x %= mo; y %= mo;
return (x + y + 2) % mo * (y - x + 1) % mo * ni % mo;
}
void End() {
f[0][0][0][0] = 1;
fo(i, 1, a[0]) {
fo(j, 0, i) {
fo(la, 0, 1) {
if(a[i] >= la)
f[i][j][0][0] += f[i - 1][j][la][0] * s2(a[i] - la, a[i] - la) % mo,
f[i][j][0][1] += f[i - 1][j][la][1] * s2(a[i] - la, a[i] - la) % mo;
f[i][j][0][0] += (f[i - 1][j][la][0] + f[i - 1][j][la][1]) % mo * s2(0, a[i] - la - 1) % mo;
f[i][j][0][1] += (f[i - 1][j][la][0] + f[i - 1][j][la][1]) % mo * s2(a[i] - la + 1, p - 1 - la) % mo;
f[i][j][0][0] %= mo; f[i][j][0][1] %= mo;
if(j == 0) continue;
f[i][j][1][0] += f[i - 1][j - 1][la][0] * s1(a[i] - la + p, a[i] - la + p) % mo;
f[i][j][1][1] += f[i - 1][j - 1][la][1] * s1(a[i] - la + p, a[i] - la + p) % mo;
f[i][j][1][0] += (f[i - 1][j - 1][la][0] + f[i - 1][j - 1][la][1]) % mo * s1(p - la, a[i] - la - 1 + p) % mo;
f[i][j][1][1] += (f[i - 1][j - 1][la][0] + f[i - 1][j - 1][la][1]) % mo * s1(a[i] - la + 1 + p, 2 * p - 1) % mo;
f[i][j][1][0] %= mo; f[i][j][1][1] %= mo;
}
}
}
}
int main() {
freopen("password.in", "r", stdin);
freopen("password.out", "w", stdout);
Init();
if(k > a[0]) {
printf("0\n");
return 0;
}
End();
ll ans = 0;
fo(i, k, a[0]) ans += f[a[0]][i][0][0];
ans = (ans % mo + mo) % mo;
printf("%lld", ans);
}