bzoj4591 / P4345 [SHOI2015]超能粒子炮·改
题意:求$\sum_{i=1}^{k}C(n,i)\%(P=2333)$
肯定要先拆开,不然怎么做呢(大雾)
把$C(n,i)$用$lucas$分解一下
于是原式$=\sum_{i=1}^{k}C(n/P,k/P)*C(n\%P,k\%P)\%P$
发现介个$k/P$是可以用整除分块搞的
于是拆开各个分块
$=C(n/P,0)*\sum_{i=0}^{P-1}C(n\%P,i)$
$+C(n/P,1)*\sum_{i=0}^{P-1}C(n\%P,i)$
$+...$
$+C(n/P,k/P-1)*\sum_{i=0}^{P-1}C(n\%P,i)$
$+C(n/P,k/P)*\sum_{i=0}^{k\%P}C(n\%P,i)$(最后一块不一定是整块,单独取出)
发现前面都有个$\sum_{i=0}^{P-1}C(n\%P,i)$,把它提出来
$=\sum_{j=0}^{k/P-1}C(n/P,j)*\sum_{i=0}^{P-1}C(n\%P,i)+C(n/P,k/P)*\sum_{i=0}^{k\%P}C(n\%P,i)$
根据$f$数组的定义再套进去
$=f[n/P][k/P-1]*f[n\%P][P-1]+C(n/P,k/P)*f[k\%P][n\%P]$
先预处理下标$<P$的$f$数组和组合数$C$,再递归一下,$C(n/P,k/P)$用$Lucas$定理搞
end.
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 typedef long long ll; 6 const int P=2333; 7 int t;ll n,k,c[P+1][P+1],f[P+1][P+1]; 8 ll lucas(ll a,ll b){ 9 if(a<b) return 0; 10 if(a==b) return 1; 11 return b?lucas(a/P,b/P)*c[a%P][b%P]%P:1; 12 } 13 ll F(ll a,ll b){ 14 if(b<0) return 0; 15 if(!a||!b) return 1; 16 if(a<P&&b<P) return f[a][b]; 17 ll r1=f[a%P][P-1]*F(a/P,b/P-1)%P; 18 ll r2=lucas(a/P,b/P)*f[a%P][b%P]%P; 19 return (r1+r2)%P; 20 } 21 int main(){ 22 for(int i=0;i<=P;++i){ 23 c[i][0]=c[i][i]=1; 24 for(int j=1;j<i;++j) 25 c[i][j]=(c[i-1][j-1]+c[i-1][j])%P; 26 } 27 for(int i=0;i<=P;++i){ 28 f[i][0]=1; 29 for(int j=1;j<=P;++j)//注意f[P][P]以内的都要处理到 30 f[i][j]=(f[i][j-1]+c[i][j])%P; 31 } 32 scanf("%d",&t); 33 while(t--){ 34 scanf("%lld%lld",&n,&k); 35 printf("%lld\n",F(n,k)); 36 }return 0; 37 }