bzoj4591 / P4345 [SHOI2015]超能粒子炮·改
Posted kafuuchino
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 ",F(n,k)); 36 }return 0; 37 }
以上是关于bzoj4591 / P4345 [SHOI2015]超能粒子炮·改的主要内容,如果未能解决你的问题,请参考以下文章
BZOj-4591: [Shoi2015]超能粒子炮·改 (Lucas+排列组合)