bzoj4591 / P4345 [SHOI2015]超能粒子炮·改

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 }
View Code

 

posted @ 2018-11-05 15:28  kafuuchino  阅读(159)  评论(0编辑  收藏  举报