Problem B. Harvest of Apples
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 989 Accepted Submission(s): 377
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≤10^5) denoting the number of test cases.
Each test case consists of one line with two integers n,m (1≤m≤n≤10^5).
Output
For each test case, print an integer representing the number of ways modulo 10^9+7.
Sample Input
2
5 2
1000 500
Sample Output
16 924129523
Source
2018 Multi-University Training Contest 4
大致题意:一个组合数学裸题,直接求 即可。
如果令,可以得到关于s(n,m)的递推式:
由此,如果我们知道S(n,m),我们就可以知道在O(1)的时间复杂度内求出S(n+1,m)、S(n-1,m)、S(n,m+1)和S(n,m-1)这四个的数值。那么,我们把n和m看作区间询问的左右端点,对于读入的T个询问,我们完全可以按照莫队算法的区间移动的方式来解决这道题。O(1)转移已经给出,直接套用模板即可。时间复杂度。具体见代码:
#include<bits/stdc++.h>
#define LL long long
#define mod 1000000007
#define IO ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define N 100010
using namespace std;
struct query{int l,r,block,id;} q[N<<2];
LL inv[N],fac[N],ans[N];
int blocks;
bool cmp(query a,query b)
{
if (a.block!=b.block) return a.l<b.l;
if (a.block&1) return a.r<b.r; return a.r>b.r;
}
void init()
{
fac[1]=fac[0]=1;
inv[1]=inv[0]=1;
for(int i=2;i<N;i++)
{
fac[i]=fac[i-1]*i%mod;
inv[i]=(mod-mod/i)*inv[mod%i]%mod;
}
for(int i=2;i<N;i++)
inv[i]=inv[i-1]*inv[i]%mod;
}
LL C(int x,int y)
{
if (y>x) return 0;
return fac[x]*inv[y]%mod*inv[x-y]%mod;
}
int main()
{
init();
IO;int T;cin>>T;
blocks=sqrt(T)+1;
for(int i=1;i<=T;i++)
{
int n,m;
cin>>n>>m;
q[i]=query{n,m,n/blocks,i};
}
sort(q+1,q+T+1,cmp);
int l=1,r=0,res=1;
for(int i=1;i<=T;i++)
{
while(l<q[i].l)
{
res=res*2%mod-C(l,r);
if (res<0) res+=mod;
l++;
}
while(l>q[i].l)
{
l--;
res=(res+C(l,r))%mod*inv[2]%mod;
}
while(r<q[i].r)
{
r++;
res=(res+C(l,r))%mod;
}
while(r>q[i].r)
{
res=(res-C(l,r)+mod)%mod;
r--;
}
ans[q[i].id]=res;
}
for(int i=1;i<=T;i++)
cout<<ans[i]<<endl;
return 0;
}