库默尔定理:
C(n,m)C(n,m)C(n,m)中含有的质数p幂次
= n−mn - mn−m在p进制下的借位次数
= m+(n−m)m + (n - m)m+(n−m)在p进制下的进位次数。
原理:
Ans=∑k>0npk−(n−mpk+mpk)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)从pkp^kpk起的高位与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);
}