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

时间:2023-03-08 21:38:28

任意门: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 (1≤T≤105) denoting the number of test cases.
Each test case consists of one line with two integers n,m (1≤m≤n≤105).
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.csdn.net/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:

 #include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
#include<queue>
#include<cmath>
#include<set>
#define INF 0x3f3f3f3f
#define LL long long
using namespace std;
const LL MOD = 1e9+;
const int MAXN = 1e5+;
LL N, M;
LL fac[MAXN], inv[MAXN];
struct Query
{
int L, R, id, block;
bool operator < (const Query &p)const{
if(block == p.block) return R < p.R;
return block < p.block;
}
}Q[MAXN];
LL res, rev2;
LL ans[MAXN]; LL q_pow(LL a, LL b)
{
LL pans = 1LL;
while(b){
if(b&) pans = pans*a%MOD;
b>>=1LL;
a = a*a%MOD;
}
return pans;
} LL C(int n, int k)
{
return fac[n]*inv[k]%MOD*inv[n-k]%MOD;
} void init()
{
rev2 = q_pow(, MOD-); // 2的逆元
fac[] = fac[] = ;
for(LL i = ; i < MAXN; i++){ //预处理阶乘
fac[i] = fac[i-]*i%MOD;
} inv[MAXN-] = q_pow(fac[MAXN-], MOD-); //逆推预处理阶乘的逆元
for(int i = MAXN-; i >= ; i--){
inv[i] = inv[i+]*(i+)%MOD;
}
} void addN(int posL, int posR)
{
res = (*res%MOD-C(posL-, posR)%MOD + MOD)%MOD;
} void addM(int posL, int posR)
{
res = (res+C(posL, posR))%MOD;
} void delN(int posL, int posR)
{
res = (res+C(posL-, posR))%MOD*rev2%MOD;
} void delM(int posL, int posR)
{
res = (res - C(posL, posR) + MOD)%MOD;
} int main()
{
int T_case;
init();
int len = (int)sqrt(MAXN*1.0);
scanf("%d", &T_case);
for(int i = ; i <= T_case; i++){
scanf("%d%d", &Q[i].L, &Q[i].R);
Q[i].id = i;
Q[i].block = Q[i].L/len;
}
sort(Q+, Q++T_case);
res = ;
int curL = , curR = ;
for(int i = ; i <= T_case; i++){
while(curL < Q[i].L) addN(++curL, curR);
while(curR < Q[i].R) addM(curL, ++curR);
while(curL > Q[i].L) delN(curL--, curR);
while(curR > Q[i].R) delM(curL, curR--);
ans[Q[i].id] = res;
}
for(int i = ; i <= T_case; i++){
printf("%lld\n", ans[i]);
} return ; }