题目大意:给出两个整数 n,k,n,k<=1018
求
一道不错的Lucas定理的题。首先这道题有一个很重要的特点,就是模数非常的小。
我们可以考虑对式子进行一些改动,以n=13,k=7,模数是3为例
C(13,0)+C(13,1)+C(13,2)+C(13,3)+C(13,4)+C(13,5)+C(13,6)+C(13,7)
利用Lucas定理,得
C(4,0)∗C(1,0)+C(4,0)∗C(1,1)+C(4,0)∗C(1,2)+C(4,1)∗C(1,0)+C(4,1)∗C(1,1)+C(4,1)∗C(1,2)+C(4,2)∗C(1,0)+C(4,2)∗C(1,1)
通过观察,式子可以变成
∑k/p−1i=0C(n/p,i) 可以递归求解。然后剩下的两部分都可以预处理前缀和,快速的求解。
#include
#include
#include
#include
#include
#define LL long long
#define p 2333
using namespace std;
LL n,k;
int T,jc[3000],inv[3000],c[3000][3000],sum[3000][3000];
int quickpow(int num,int x)
{
int base=num%p; int ans=1;
while (x) {
if (x&1) ans=ans*base%p;
x>>=1;
base=base*base%p;
}
return ans;
}
int C(LL n,LL m)
{
if (m>n) return 0;
return jc[n]*quickpow(jc[m],p-2)%p*quickpow(jc[n-m],p-2)%p;
}
int calc(LL n,LL m)
{
if (m==0) return 1;
return calc(n/p,m/p)*c[n%p][m%p]%p;
}
int solve(LL n,LL m)
{
if (m<0) return 0;
if (m==0) return 1;
LL y=m/p;
int ans=0; ans=sum[n%p][m%p]*calc(n/p,m/p)%p;
int t1=solve(n/p,m/p-1);
if (y) t1=t1*sum[n%p][p-1];
return (t1+ans)%p;
}
int main()
{
freopen("a.in","r",stdin);
freopen("my.out","w",stdout);
scanf("%d",&T);
jc[0]=1;
for (int i=1;i<=p;i++) jc[i]=jc[i-1]*i%p;
for (int i=0;i<=p;i++) inv[i]=quickpow(jc[i],p-2);
for (int i=0;i<=p;i++) c[i][0]=1;
for (int i=1;i<=p;i++)
for (int j=1;j<=i;j++) c[i][j]=(c[i-1][j]+c[i-1][j-1])%p;
for (int i=0;i<=p;i++) {
sum[i][0]=c[i][0];
for (int j=1;j<=p-1;j++) sum[i][j]=(sum[i][j-1]+c[i][j])%p;
}
while (T--) {
scanf("%lld%lld",&n,&k);
int ans=solve(n,k);
printf("%d\n",ans);
}
}