算法:
我们设每一组n与k的数据的所求答案为,(聪明的人已经发现了秘密所在)
则,设模数p=2333.
根据卢卡斯定理,原式=,
且可以把它拆成
进一步化为
=
根据对CNLZP(n,k)的定义,原式=
此时计算的时间复杂度已绰绰有余(没错就是笔者不会算),预处理组合数,套用卢卡斯定理即可。
借https://35178.blog.luogu.org/solution-p4345博客中的时间复杂度:
Code:
#include<bits/stdc++.h>
#define rep(i,j,k) for(int i=j;i<=k;i++)
#define rep2(i,j,k) for(int i=j;i>=k;i--)
#define mo 2333
using namespace std;
template<typename T> void read(T &num){
char c=getchar();num=0;T f=1;
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){num=(num<<3)+(num<<1)+(c^48);c=getchar();}
num*=f;
}
template<typename T> void qwq(T x){
if(x>9)qwq(x/10);
putchar(x%10+'0');
}
template<typename T> void write(T x){
if(x<0){x=-x;putchar('-');}
qwq(x);putchar('\n');
}
int c[2400][2400];
inline void C(){
rep(i,0,mo-1){
rep(j,0,mo-1){
if(i<j)break;
if(i==j||j==0){c[i][j]=1;}
else{c[i][j]=(c[i-1][j]+c[i-1][j-1])%mo;}
}
}
return;
}
inline int Lucas(long long n,long long m){
if(n<m)return 0;
if(m==0||n==m)return 1;
return (c[n%mo][m%mo]*Lucas(n/mo,m/mo))%mo;
}
int ans[2400][2400];
inline int CNLZP(long long n,long long k){
if(k<0)return 0;
if(n<mo&&k<mo)return ans[n][k];
int temp=(CNLZP(n%mo,mo-1)*CNLZP(n/mo,k/mo-1))%mo;
int temp2=(Lucas(n/mo,k/mo)*CNLZP(n%mo,k%mo))%mo;
temp=(temp+temp2)%mo;
return temp;
}
int main(){
int t;read(t);
C();
rep(i,0,mo-1){
ans[i][0]=1;
rep(j,1,mo-1){
ans[i][j]=(ans[i][j-1]+c[i][j])%mo;
}
}
while(t--){
long long n,k;read(n);read(k);
write(CNLZP(n,k));
}
return 0;
}