思路很妙的$Lucas$。
设$f(n,k)=\sum\limits_{i=0}^kC_n^i$
套上卢卡斯:
$f(n,k)=\sum\limits_{i=0}^kC_{n/p}^{i/p}C_{n\% p}^{i\% p}$
$i$每增长$p$,$i/p$才会加$1$。把$C_{n/p}^{i/p}$拆出来:
$=\left(\sum\limits_{i=0}^{k/p-1}C_{n/p}^i\sum\limits_{j=0}^{p-1}C_{n\% p}^{j}\right)+C_{n/p}^{k/p}\sum\limits_{i=0}^{k\% p}C_{n\% p}^{i}$
$=f(n/p,k/p-1)f(n\% p,p-1)+C_{n/p}^{k/p}f(n\% p,k\% p)$
$f$相当于是组合数的前缀和,$O(p^2)$预处理$0\sim p-1$的$f$,递归计算$f(n/p,k/p-1)$,$C_{n/p}^{k/p}$用卢卡斯计算即可。
注意特判递归时$k<0$的情况。
复杂度:$O(t\log_p^2n)$
代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#define maxn 100005
#define inf 0x3f3f3f3f
const int mod = 2333;
using namespace std;
inline int read(){
int x=0,y=0;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')y=1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return y?-x:x;
}
template<typename T>
inline T read(){
T x=0;
int y=0;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')y=1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return y?-x:x;
}
int c[mod+1][mod+1],f[mod+1][mod+1];
int C(long long n,long long m){//注意long long
if(n<m)return 0;
if(n>=mod)return C(n/mod,m/mod)*C(n%mod,m%mod)%mod;
return c[n][m];
}
int F(long long n,long long k){
if(k<0)return 0;
if(k>=mod||n>=mod)return (f[n%mod][mod-1]*F(n/mod,k/mod-1)%mod+C(n/mod,k/mod)*f[n%mod][k%mod]%mod)%mod;
return f[n][k];
}
int main(){
c[0][0]=1;
for(register int i=0;i<mod;++i)f[0][i]=1;
for(register int i=1;i<mod;++i){
c[i][0]=f[i][0]=1;
for(register int j=1;j<mod;++j)
c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod,f[i][j]=(f[i][j-1]+c[i][j])%mod;
}
int t=read();
long long n,k;
while(t--)n=read<long long>(),k=read<long long>(),printf("%d\n",F(n,k));
}