HDU 6333 Harvest of Apples (分块、数论)

题目连接:Harvest of Apples

题意:给出一个n和m,求C(0,n)+C(1,n)+.....+C(m,n)。(样例组数为1e5)

题解:首先先把阶乘和逆元预处理出来,这样就可O(1)将C(m,n)求出来了。但这样还是会超时,所以接下来要分块,每隔500个处理出C(1~m,n)的结果。然后还要知道一个性质 C(a,b) = ∑C(t1,x)*C(t2,y)  (x+y<=b),这样我们就可以将给出的m和n分为两个组,其中一个组中元素的个数为500的倍数。然后我们对于另一个组枚举可能的t2然后求和,每次询问最大的操作次数就变成了500次。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long LL;
 4 const LL mod = 1e9 + 7;
 5 typedef pair<int,int> P;
 6 const int MAX_N = 1e5+9;
 7 int N,M,T,S;
 8 LL Jc[MAX_N];
 9 LL ni_[MAX_N];
10 LL tran[309][MAX_N];
11 LL tr[509][509];
12 //费马小定理求逆元
13 LL pow(LL a, LL n, LL p)    //快速幂 a^n % p
14 {
15     LL ans = 1;
16     while(n)
17     {
18         if(n & 1) ans = ans * a % p;
19         a = a * a % p;
20         n >>= 1;
21     }
22     return ans;
23 }
24 
25 LL niYuan(LL a, LL b)   //费马小定理求逆元
26 {
27     return pow(a, b - 2, b);
28 }
29 
30 void calJc()    //求maxn以内的数的阶乘
31 {
32     Jc[0] = Jc[1] = 1;
33     for(LL i = 2; i < MAX_N; i++)
34         Jc[i] = Jc[i - 1] * i % mod;
35 }
36 void calni(){
37     for(int i=0;i<MAX_N;i++){
38         ni_[i] = niYuan(Jc[i],mod);
39     }
40 }
41 
42 LL C(LL a, LL b)    //计算C(a, b)
43 {
44     return Jc[a] * ni_[b] % mod
45         * ni_[a-b] % mod;
46 }
47 
48 void init(){
49     for(int i=1;i<MAX_N/500;i++){
50         for(int j=0;j<MAX_N;j++){
51             tran[i][j] = C(500*i,j);
52             if(j>0) tran[i][j] = (tran[i][j] + tran[i][j-1])%mod;
53         }
54     }
55 
56     for(int i=0;i<509;i++){
57         for(int j=0;j<509;j++){
58             tr[i][j] = C(i,j);
59         }
60     }
61 }
62 int main(){
63     calJc();
64     calni();
65     init();
66     //cout<<"OK"<<endl;
67     cin>>T;
68     while(T--){
69         LL a,b;
70         scanf("%lld%lld",&a,&b);
71         LL ans = 0;
72         if(a < 500){
73             for(int i=0;i<=b;i++)
74                 ans = (ans + tr[a][i])%mod;
75         }
76         else{
77             LL t1 = a / 500;
78             LL t2 = a - t1*500;
79             for(int i=0;i<=min(b,t2);i++){
80                 ans = (ans + tr[t2][i]*tran[t1][min(b - i,t1*500)])%mod;
81             }
82         }
83         printf("%lld\n",ans);
84 
85     }
86     return 0;
87 }

 

posted @ 2018-08-02 09:30  会打架的程序员不是好客服  阅读(847)  评论(2编辑  收藏  举报