「SHOI2015」超能粒子炮・改
「SHOI2015」超能粒子炮・改
给你$T$组询问,每组询问给定参数$n,k$,计算$\sum\limits_^k\dbinom\bmod 2333$.
\(T\leq10^5,n,k\leq10^{18}\).
这题其实是$\operatorname$定理的一个简单扩展。
方便起见,令$p=2333$.
首先利用$\operatorname\(定理化简所求和式,由\)\dbinom\equiv\dbinom{n/p}{m/p}\times\dbinom{n%p}{m%p}\pmod p$得:
\[
\begin{align*}
\sum_{i=0}^{k}\binom{n}{i}&\equiv
\sum_{i=0}^k\binom{n/p}{i/p}\binom{n\%p}{i\%p}\\
&\equiv\sum_{i=0}^{p-1}\binom{n\%p}{i}\sum_{j=0}^{k/p-1}\binom{n/p}{j}+\binom{n/p}{k/p}\sum_{i=0}^{k\%p}\binom{n\%p}{i}
\end{align*}
\]
在该和式中,$\sum\limits_\dbinom{n%p}$和 $\sum\limits_{k%p}\dbinom{n%p}\(都可以用\)\Omicron(p^2)\(的时间复杂度预处理,而\)\dbinom{n/p}{k/p}\(可以利用\)\operatorname\(定理在\)\Omicron(\log_pn)$的时间复杂度内计算。
所以我们只要能够计算出$\sum\limits_{k/p-1}\dbinom{n/p}\(就可以快速计算出\)\sum\limits_\dbinom$,而这两个式子形式相同,并且每次$n,k$规模减半,所以可以递归解决,并且次数不超过$\log n$次。
所以总时间复杂度为$\Omicron(T\log2n+p2)$.
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=2333;
int T,c[mod+5][mod+5],pre[mod+5][mod+5];
inline ll read(){
ll res=0,f_f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') f_f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') res=(res<<3)+(res<<1)+(ch-'0'),ch=getchar();
return res*f_f;
}
inline void Gmo(int &x){
while(x<0) x+=mod;
while(x>=mod) x-=mod;
}
inline void init(){
c[0][0]=1;
for (int i=1;i<mod;i++){
c[i][i]=1,c[i][0]=1;
for (int j=1;j<i;j++){
c[i][j]=c[i-1][j-1]+c[i-1][j];
Gmo(c[i][j]);
}
}
for (int i=0;i<mod;i++){
pre[i][0]=c[i][0];
for (int j=1;j<mod;j++){
pre[i][j]=pre[i][j-1]+c[i][j];
Gmo(pre[i][j]);
}
}
}
inline int Lucas(ll n,ll m,int p){
if(m==0) return 1;
return 1ll*Lucas(n/p,m/p,p)*c[n%p][m%p]%p;
}
inline int calc(ll n,ll k,int p){
int x=1ll*Lucas(n/p,k/p,p)*pre[n%p][k%p]%mod;
if(k<p) return x;
int y=1ll*pre[n%p][p-1]*calc(n/p,k/p-1,p);
return (x+y)%mod;
}
int main(){
T=read(),init();
while(T--){
ll n=read(),k=read();
printf("%d\n",calc(n,k,mod));
}
return 0;
}

浙公网安备 33010602011771号