根据lucas定理,我们有
ans(n,k)=ans(⌊np⌋,⌊kp⌋−1)∗∑i=0p−1(n%pi)+(⌊n/p⌋⌊k/p⌋)∑i=0k%p(n%pi)
其中 ans 项递归计算,组合数用lucas暴力算,和式 O(p2) 预处理。
复杂度 O(p2+Tlognlogp) 。
#include<cstdio>
#include<algorithm>
using namespace std;
#define LL long long
const int p=2333;
int pow(int base,int k)
{
int ret=1;
for (;k;k>>=1,base=base*base%p)
if (k&1) ret=ret*base%p;
return ret;
}
int fac[p+10],inv[p+10],sum[p+10][p+10];
int c(LL n,LL k)
{
if (k>n) return 0;
if (n<p&&k<p) return fac[n]*inv[k]%p*inv[n-k]%p;
return c(n%p,k%p)*c(n/p,k/p)%p;
}
int solve(LL n,LL k)
{
int ret=0,tem=0;
if (n<p&&k<p) return sum[n][k];
return (sum[n%p][p-1]*solve(n/p,k/p-1)%p+sum[n%p][k%p]*c(n/p,k/p)%p)%p;
}
int main()
{
LL n,k;
inv[0]=fac[0]=1;
for (int i=1;i<p;i++) fac[i]=fac[i-1]*i%p;
inv[p-1]=pow(fac[p-1],p-2);
for (int i=p-2;i;i--) inv[i]=inv[i+1]*(i+1)%p;
for (int i=0;i<p;i++)
{
sum[i][0]=1;
for (int j=1;j<p;j++) sum[i][j]=(sum[i][j-1]+c(i,j))%p;
}
int T;
scanf("%d",&T);
while (T--)
{
scanf("%lld%lld",&n,&k);
printf("%d\n",solve(n,k));
}
}