根據lucas定理,我們有
ans(n,k)=ans(⌊np⌋,⌊kp⌋−1)∗∑i=0p−1(n%pi)+(⌊n/p⌋⌊k/p⌋)∑i=0k%p(n%pi) ans(n,k)=ans(\lfloor\frac n p \rfloor,\lfloor \frac k p\rfloor -1)*\sum_{i=0}^{p-1}\binom{n\%p}i+\binom{\lfloor n/p\rfloor}{\lfloor k/p\rfloor}\sum_{i=0}^{k\%p}\binom{n\%p}i
其中 ans ans項遞迴計算,組合數用lucas暴力算,和式 O(p2) O(p^2)預先處理。
複雜度 O(p2+Tlognlogp) O(p^2+T\log n\log p)。
#include<cstdio>#include<algorithm>using namespace std;#define LL long longconst 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)); }}