2018 Multi-University Training Contest 4 Problem B. Harvest of Apples 【莫队+排列组合+逆元预处理技巧】...

本文解决HDU 6333问题,即计算从N个苹果中最多选取m个的不同方式数量。通过使用莫队算法,结合公式推导和逆元预处理技巧,实现对大量数据的有效处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

任意门:http://acm.hdu.edu.cn/showproblem.php?pid=6333

Problem B. Harvest of Apples

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 4043    Accepted Submission(s): 1560


Problem Description
There are  n apples on a tree, numbered from 1 to n.
Count the number of ways to pick at most m apples.
 

 

Input
The first line of the input contains an integer  T (1T105) denoting the number of test cases.
Each test case consists of one line with two integers n,m (1mn105).
 

 

Output
For each test case, print an integer representing the number of ways modulo  109+7.
 

 

Sample Input
2
5 2
1000 500
 

 

Sample Output
16
924129523
 

 

Source

 

题意概括:

有 N 个苹果,问最多选 m 个苹果的方案有多少种?

 

解题思路:

大佬讲的很好了。

https://blog.youkuaiyun.com/codeswarrior/article/details/81359075

推出四个公式,算是一道比较裸的莫队了。

Sm−1n=Smn−CmnSnm−1=Snm−Cnm
Sm+1n=Smn+Cm+1nSnm+1=Snm+Cnm+1(或者Smn=Sm−1n+CmnSnm=Snm−1+Cnm)

Smn+1=2Smn−CmnSn+1m=2Snm−Cnm
Smn−1=Smn+Cmn−12Sn−1m=Snm+Cn−1m2(或者Smn=Smn+1+Cmn2Snm=Sn+1m+Cnm2)

需要注意的点较多:

1、精度问题,注意数据范围

2、为了保证精度,除法需要转换为逆元,预处理逆元的技巧

 

AC code:

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<iostream>
  4 #include<cstring>
  5 #include<vector>
  6 #include<queue>
  7 #include<cmath>
  8 #include<set>
  9 #define INF 0x3f3f3f3f
 10 #define LL long long
 11 using namespace std;
 12 const LL MOD = 1e9+7;
 13 const int MAXN = 1e5+10;
 14 LL N, M;
 15 LL fac[MAXN], inv[MAXN];
 16 struct Query
 17 {
 18     int L, R, id, block;
 19     bool operator < (const Query &p)const{
 20         if(block == p.block) return R < p.R;
 21         return block < p.block;
 22     }
 23 }Q[MAXN];
 24 LL res, rev2;
 25 LL ans[MAXN];
 26 
 27 LL q_pow(LL a, LL b)
 28 {
 29     LL pans = 1LL;
 30     while(b){
 31         if(b&1) pans = pans*a%MOD;
 32         b>>=1LL;
 33         a = a*a%MOD;
 34     }
 35     return pans;
 36 }
 37 
 38 LL C(int n, int k)
 39 {
 40     return fac[n]*inv[k]%MOD*inv[n-k]%MOD;
 41 }
 42 
 43 void init()
 44 {
 45     rev2 = q_pow(2, MOD-2);                     // 2的逆元
 46     fac[0] = fac[1] = 1;
 47     for(LL i = 2; i < MAXN; i++){              //预处理阶乘
 48         fac[i] = fac[i-1]*i%MOD;
 49     }
 50 
 51     inv[MAXN-1] = q_pow(fac[MAXN-1], MOD-2);    //逆推预处理阶乘的逆元
 52     for(int i = MAXN-2; i >= 0; i--){
 53         inv[i] = inv[i+1]*(i+1)%MOD;
 54     }
 55 }
 56 
 57 void  addN(int posL, int posR)
 58 {
 59     res = (2*res%MOD-C(posL-1, posR)%MOD + MOD)%MOD;
 60 }
 61 
 62 void addM(int posL, int posR)
 63 {
 64     res = (res+C(posL, posR))%MOD;
 65 }
 66 
 67 void delN(int posL, int posR)
 68 {
 69     res = (res+C(posL-1, posR))%MOD*rev2%MOD;
 70 }
 71 
 72 void delM(int posL, int posR)
 73 {
 74     res = (res - C(posL, posR) + MOD)%MOD;
 75 }
 76 
 77 int main()
 78 {
 79     int T_case;
 80     init();
 81     int len = (int)sqrt(MAXN*1.0);
 82     scanf("%d", &T_case);
 83     for(int i = 1; i <= T_case; i++){
 84         scanf("%d%d", &Q[i].L, &Q[i].R);
 85         Q[i].id = i;
 86         Q[i].block = Q[i].L/len;
 87     }
 88     sort(Q+1, Q+1+T_case);
 89     res = 2;
 90     int curL = 1, curR = 1;
 91     for(int i = 1; i <= T_case; i++){
 92         while(curL < Q[i].L) addN(++curL, curR);
 93         while(curR < Q[i].R) addM(curL, ++curR);
 94         while(curL > Q[i].L) delN(curL--, curR);
 95         while(curR > Q[i].R) delM(curL, curR--);
 96         ans[Q[i].id] = res;
 97     }
 98     for(int i = 1; i <= T_case; i++){
 99         printf("%lld\n", ans[i]);
100     }
101 
102     return 0;
103 
104 }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值