https://codeforces.com/problemset/problem/582/D
题意
给定p,a(1~1e9),求有多少对(n,k)满足 C n k C_{n}^{k} Cnk可被 p a p^a pa整除(1<=k<=n<=A, A= 1 0 1000 10^{1000} 101000)
解题
分析下,n!所含的p的次数相当于是n在p进制下按位加权的数位和,
这样
C
n
k
=
n
!
k
!
(
n
−
k
)
!
C_{n}^{k}=\frac{n!}{k!(n-k)!}
Cnk=k!(n−k)!n!所含的p的次数为k+(n-k)在p进制下的进位次数(可能要想一下,或可直接用一个叫kummer定理的东西,意思一样)
然后把dp出来就好
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 1e4 + 100;
const int mo = 1e9 + 7;
int aa[3500], cnt, bb[3500], tot, t[3500], cnt2;
int f[3500][3500][2][2];
const int inv2 = 5e8 + 4;
inline int add(ll a, ll b) {
return a+b>mo?a+b-mo:a+b;
}
inline int mns(int a, int b) {
return a-b<0?a-b+mo:a-b;
}
void cov(int p) {
ll val = 0; int flg = 0;
while (1) {
flg = 0;
for (int i = 0; i < cnt; ++i) {
val = (1ll*val * 10 +aa[i]);
if (val < (1ll)*p)t[tot++] = 0;
else {
flg = 1;
t[tot++] = val / p;
val %= p;
}
}
for (int i = 0; i < cnt; ++i)aa[i] = t[i];
tot = 0;
bb[cnt2++] = val, val = 0;
if (val < p && !flg)break;
}
}
signed main() {
int p, a;
scanf("%d%d", &p, &a);
aa[cnt] = getchar();
char c = '9';
while (c = getchar()) {
if (c > '9' || c < '0')break;
aa[cnt++] = c - '0';
}
cov(p);
if(cnt2<a){
printf("0\n");
}
else{
f[cnt2+1][0][0][1] = 1;
int p1= 1ll*(p + 1) * p % mo * inv2 % mo,p2= 1ll*(p - 1) * p % mo * inv2 % mo;
for (int i = cnt2; i; --i) {
int x1 = 1ll*(bb[i-1]+1)*bb[i-1]%mo*inv2%mo,x2= 1ll*(bb[i - 1] - 1) * bb[i - 1] % mo * inv2 % mo, px= 1ll*p * bb[i - 1] % mo;
for (int j = 0; j <=cnt2 - i; ++j) {
int tmp = f[i+1][j][0][0];
f[i][j][0][0]=add(f[i][j][0][0], 1ll*tmp * p1 % mo);
f[i][j+1][1][0]=add(f[i][j+1][1][0], 1ll*tmp * p2 % mo);
tmp = f[i+1][j][1][0];
f[i][j][0][0]=add(f[i][j][0][0],1ll* tmp * p2 % mo);
f[i][j+1][1][0]=add(f[i][j+1][1][0], 1ll*tmp * p1 % mo);
tmp = f[i+1][j][0][1];
f[i][j][0][0]=add(f[i][j][0][0], 1ll*tmp*x1%mo);
f[i][j][0][1]=add(f[i][j][0][1], 1ll*tmp*(bb[i-1]+1)%mo);
f[i][j+1][1][0]=add(f[i][j+1][1][0], 1ll*tmp * x2 % mo);
f[i][j+1][1][1]=add(f[i][j+1][1][1], 1ll*tmp*bb[i-1]%mo);
tmp = f[i+1][j][1][1];
f[i][j][0][0]=add(f[i][j][0][0], 1ll*tmp*mns(px, x1)%mo);
f[i][j][0][1]=add(f[i][j][0][1], 1ll*tmp*(p -bb[i-1] - 1)%mo);
f[i][j+1][1][0]=add(f[i][j+1][1][0], 1ll*tmp * mns(px, x2) % mo);
f[i][j+1][1][1]=add(f[i][j+1][1][1], 1ll*tmp*(p - bb[i-1])%mo);
}
}
int ans = 0;
for(int i=a;i<=cnt2;++i)ans=add(ans,add(f[1][i][0][1],f[1][i][0][0]));
printf("%d\n",ans);
}
return 0;
}