bzoj4591 [Shoi2015]超能粒子炮·改

Description

曾经发明了脑洞治疗仪&超能粒子炮的发明家SHTSC又公开了他的新发明:超能粒子炮·改--一种可以发射威力更加强大的粒子流的神秘装置。超能粒子炮·改相比超能粒子炮,在威力上有了本质的提升。它有三个参数n,k。它会向编号为0到k的位置发射威力为C(n,k) mod 2333的粒子流。现在SHTSC给出了他的超能粒子炮·改的参数,让你求其发射的粒子流的威力之和模2333。

Input

第一行一个整数t。表示数据组数。
之后t行,每行二个整数n,k。含义如题面描述。
k<=n<=10^18,t<=10^5

Output

t行每行一个整数,表示其粒子流的威力之和模2333的值。

Sample Input

1
5 5

Sample Output

32

 

正解:组合数学+$lucas$定理。

$Ans=\sum_{k=0}^{m}\binom{n}{k} \ mod \ p$

令$\binom{n}{k} \ mod  \ p=lucas(n,k,p)$,那么由$lucas$定理,$lucas(n,k,p)=\binom{n \ mod \ p}{k \ mod \ p}*lucas(n/p,k/p,p)$

我们把上式带入$Ans$中,令$m=p*q+r$,可以发现$Ans=\sum_{k=0}^{n \ mod \ p}\binom{n \ mod \ p}{k}*\sum_{k=0}^{q-1}\binom{n/p}{k} \ mod \ p+\sum_{k=0}^{r}\binom{n \mod \ p}{k}*lucas(n/p,q,p)$

预处理出$p$以内的组合数和杨辉三角每一层的前缀和,直接写一个递归函数调用即可。

因为递归函数和$lucas$函数的层数都不超过$log_{p}n$层,所以单次询问复杂度很低,只有大约$40$次运算。

 

 1 //It is made by wfj_2048~
 2 #include <algorithm>
 3 #include <iostream>
 4 #include <cstring>
 5 #include <cstdlib>
 6 #include <cstdio>
 7 #include <vector>
 8 #include <cmath>
 9 #include <queue>
10 #include <stack>
11 #include <map>
12 #include <set>
13 #define inf (1<<30)
14 #define rhl (2333)
15 #define il inline
16 #define RG register
17 #define ll long long
18 #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
19 
20 using namespace std;
21 
22 ll sum[3010][3010],c[3010][3010],n,m;
23 
24 il ll gi(){
25     RG ll x=0,q=1; RG char ch=getchar();
26     while ((ch<'0' || ch>'9') && ch!='-') ch=getchar();
27     if (ch=='-') q=-1,ch=getchar();
28     while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar();
29     return q*x;
30 }
31 
32 il void pre(){
33     sum[0][0]=c[0][0]=1;
34     for (RG ll i=1;i<rhl;++i){
35     sum[i][0]=c[i][0]=c[i][i]=1;
36     for (RG ll j=1;j<i;++j){
37         c[i][j]=c[i-1][j-1]+c[i-1][j];
38         if (c[i][j]>=rhl) c[i][j]-=rhl;
39         sum[i][j]=sum[i][j-1]+c[i][j];
40         if (sum[i][j]>=rhl) sum[i][j]-=rhl;
41     }
42     sum[i][i]=sum[i][i-1]+1;
43     }
44     return;
45 }
46 
47 il ll lucas(RG ll n,RG ll m){
48     if (!m) return 1; RG ll res=c[n%rhl][m%rhl];
49     if (!res) return 0; return res*lucas(n/rhl,m/rhl)%rhl;
50 }
51 
52 il ll calc(RG ll n,RG ll m){
53     if (m<0) return 0; if (!m) return 1;
54     RG ll k=m/rhl,ans=sum[n%rhl][min(m-k*rhl,n%rhl)]*lucas(n/rhl,k)%rhl;
55     return (ans+sum[n%rhl][n%rhl]*calc(n/rhl,k-1))%rhl;
56 }
57 
58 int main(){
59     File("lucas");
60     RG ll T=gi(); pre();
61     while (T--){
62     n=gi(),m=gi();
63     printf("%lld\n",calc(n,m));
64     }
65     return 0;
66 }

 

posted @ 2017-07-03 16:14  wfj_2048  阅读(181)  评论(0编辑  收藏  举报