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≤1e5) denoting the number of test cases.
Each test case consists of one line with two integers n,m (1≤m≤n≤1e5).
Output
For each test case, print an integer representing the number of ways modulo 1e9+7.
Sample Input
2
5 2
1000 500
Sample Output
16
924129523
Source
2018 Multi-University Training Contest 4
题意:让你求 范围:i属于[0,m] 我们把左边式子简称为S(n,m)
2000ms的时限 O(T*m)的复杂度无法按正常的求和做。
所以根据这个题的特性,离线查询,可以使用莫队算法。(打比赛时,QAQ太菜了,学的东西还是太少了)
我们根据组合数的公式,可以推出以下公式:
S(n,m) = S(n,m-1)+C(n,m)
S(n,m) = 2*S(n-1,m)-C(n-1,m)
S(n,m+1) = S(n,m)+C(n,m+1)
S(n+1,m) = 2*S(n,m)-C(n,m)
这样我们就可以找到区间S(n+1,m),S(n-1,m),S(n,m+1),S(n,m-1)
酱紫就可以利用莫队分块了
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5+5;
const int mod = 1e9+7;
struct query{
int l;
int r;
int id;
};
query e[maxn];
ll ans[maxn];
ll inv[maxn],fac[maxn];
int block;//分块数
int pos[maxn];
int curL = 1;
int curR = 1;
ll now;
ll inv2;
ll qpow(ll a,int p)
{
ll tmp = 1;
while(p){
if(1&p) tmp = (tmp*a)%mod;
a = (a*a)%mod;
p>>=1;
}
return tmp;
}
void init()
{
fac[0] = 1;
for(int i=1;i<=maxn;i++)
fac[i] = (fac[i-1]*i)%mod;
inv[maxn] = qpow(fac[maxn],mod-2);
inv2 = qpow(2,mod-2);
for(int i=maxn;i>=1;i--)
inv[i-1] = (inv[i]*i)%mod;
}
ll comb(int n,int m)
{
if(m<0 || m>n) return 0;
return fac[n]*inv[m]%mod*inv[n-m]%mod;
}
bool cmp(query a,query b)
{
return (pos[a.l] == pos[b.l])?a.r<b.r:a.l<b.l;
}
inline void addN(int posL,int posR) //S(n-1,m)时
{
now = (2*now-comb(posL-1,posR)+mod)%mod;
}
inline void addM(int posL,int posR)//S(n,m-1)时
{
now = (now+comb(posL,posR))%mod;
}
inline void delN(int posL,int posR)//S(n+1,m)时
{
now = (now+comb(posL-1,posR))%mod*inv2 %mod;
}
inline void delM(int posL,int posR)//S(n,m+1)时
{
now = (now-comb(posL,posR)+mod)%mod;
}
int main()
{
#ifdef LOCAL_FILE
freopen("in.txt","r",stdin);
#endif // LOCAL_FILE
int t;
init();
block = (int)sqrt(maxn);
scanf("%d",&t);
for(int i=1;i<=t;i++)
{
scanf("%d %d",&e[i].l,&e[i].r);
e[i].id = i;
pos[i] = i/block;//**
}
sort(e+1,e+t+1,cmp);
now = 2;//curL = curR = 1;s(1,1) = 2;
for(int i=1;i<=t;i++)
{
int L = e[i].l;
int R = e[i].r;
while(curL<L) addN(++curL,curR);
while(curR<R) addM(curL,++curR);
while(curL>L) delN(curL--,curR);
while(curR>R) delM(curL,curR--);
ans[e[i].id] = now;
}
for(int i=1;i<=t;i++)
{
printf("%I64d\n",ans[i]);
}
return 0;
}