我觉得这题挺难的,题解看来看去都是一步出结论,没什么过程,只有自己搞了。既然过了就尽量写清楚点。
这题的模数是个质数且比较小,需应用卢卡斯定理:
现在用这个定理对题目所求一步一步地展开:
设答案(暂且不加上最外面的取模):
取模,用上Lucas定理:
把p=2333代入,方便起见,先把最外面的括号和mod p去掉:
由于之前设,(暂时忽略取模)所以得到:
除开最后一列,前面共有列,所以有:
至此,结论就出来了。我们可以做一个预处理,算出。由于里的数可能很大,无法预处理,只需递归地求出即可。至于大组合数,用卢卡斯定理。
最后,不要忘记取模。
#include<cstdio>
using namespace std;
typedef long long LL;
const LL p=2333;
LL N,K,T,sum[p+1][p+1],c[p+1][p+1];
void pre()
{
int i,j;
c[0][0]=1;
for(i=1;i<p;i++)
{
c[i][0]=1;
for(j=1;j<=i;j++)
c[i][j]=(c[i-1][j]+c[i-1][j-1])%p;
}
sum[0][0]=1;
for(i=1;i<p;i++)
{
sum[i][0]=1; sum[0][i]=1;
for(j=1;j<p;j++)
sum[i][j]=(sum[i][j-1]+c[i][j])%p;
}
}
LL lucas(LL n,LL m)
{
if(n<0||m<0) return 0;
if(n<p&&m<p) return c[n][m];
return lucas(n/p,m/p)*c[n%p][m%p]%p;
}
LL calc(LL n,LL k)
{
if(k<0) return 0;
return (calc(n/p,k/p-1)*sum[n%p][p-1]+lucas(n/p,k/p)*sum[n%p][k%p])%p;
}
int main()
{
pre(); scanf("%d",&T);
while(T--)
{
scanf("%lld%lld",&N,&K);
printf("%lld\n",calc(N,K));
}
return 0;
}