库默尔定理:
C
(
n
,
m
)
C(n,m)
C(n,m)中含有的质数p幂次
=
n
−
m
n - m
n−m在p进制下的借位次数
=
m
+
(
n
−
m
)
m + (n - m)
m+(n−m)在p进制下的进位次数。
原理:
A
n
s
=
∑
k
>
0
n
p
k
−
(
n
−
m
p
k
+
m
p
k
)
Ans = \sum_{k>0}\frac n {p^k}-(\frac{n-m}{p^k} + \frac{m}{p^k})
Ans=k>0∑pkn−(pkn−m+pkm)
(都是整除)
即:(a+b)从
p
k
p^k
pk起的高位与
a
的
高
位
+
b
的
高
位
a的高位+b的高位
a的高位+b的高位是否相等,取决于该位是否接收了低位的进位。(因此最多差1)
由此,进位次数便与所含幂次扯上了关系。数位dp常用来统计这类数的个数。
以下代码是暴力dp。仅需要添加一些讨论即可获得正解。
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N = 70;
ll n,p,K;
ll g[N];
ll f[N][N][2][2];
int main(){
freopen("math.in","r",stdin);
// freopen("math.out","w",stdout);
cin>>n>>p>>K;
while(n) {
g[++g[0]] = n % p;
n /= p;
}
f[g[0]+1][0][0][1] = 1;
for(int i = g[0]; i; i--) {
for(int cnt = 0; cnt < g[0]; cnt++) {
for(int li = 0; li < 2; li++) {
for(int jw = 0; jw < 2; jw++) if (f[i + 1][cnt][jw][li]) {
for(int njw = 0; njw < 2; njw++) {
if(njw==1 && i==1) break;
for(int x = 0; x < p; x++) {
if(li && x > g[i]) break;
int nli = li && x == g[i];
int ts = g[i] + (jw ? p : 0) - njw;
if(ts - x >= p || ts - x < 0) continue;
f[i][cnt + njw][njw][nli] += f[i + 1][cnt][jw][li];
}
}
}
}
}
}
ll ans = 0;
for(int z = K; z < g[0]; z++) ans += f[1][z][0][1] + f[1][z][0][0];
printf("%lld\n",ans);
}