Problem B. Harvest of Apples
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 2263 Accepted Submission(s): 883
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
题意:
让你求C(n,0)+C(n,1)+....+C(n,m)
然后结果模上1e9+7
解析:
定义 ,不难发现 。也就是说,如果我们知道 ,就能以 O(1) 的代价计算出 S(n−1,m),S(n+1,m),S(n,m+1)S(n, m-1), ,可以采用莫队算法。
时间复杂度 。
O(1)时间求组合数的办法就是阶乘逆元打表,,所以先预处理出1-1e5的逆元,然后在求乘起来就好了。
这里还有就不得不说一说杭电C++的编译器了...一样的代码用c++就T,2s多,用G++就A了,只要0.3s....真的无话可说....
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include <vector>
#include<algorithm>
using namespace std;
typedef long long int ll;
const int MAXN = 1e5+10;
const ll MOD = 1e9+7;
int n,m;
ll ans;
ll two;
ll jc[MAXN];
ll inv[MAXN];
int pos[MAXN]; //i位置是属于第pos[i]块的,用于对询问进行排序
int res[MAXN];
struct node{
int l;
int r;
int id;
ll ans;
}q[MAXN];
bool cmp(node a,node b)
{
if(pos[a.l]==pos[b.l]) //比较与下面的代码,快了0.2s左右,也可能是数据的原因
{ //就是相邻块之间不用重新跳到开头,例如(4,8)和(10,1),(10,8),这样就可以算完(4,8)直接算(10,8)不用从头开始了,即不用把r=8变成r=1
return pos[a.l]&1?(a.r<b.r):(a.r>b.r); //
}
/*if(pos[a.l]==pos[b.l])
{
return a.r<b.r;
}*/
return a.l<b.l;
}
bool cmp1(node a,node b)
{
return a.id<b.id;
}
inline ll C(int a, int b) //计算C(a, b),a下,b上
{
if(b>a) return 0;
return jc[a] * inv[b] % MOD
* inv[a-b]%MOD;
}
inline void update1(int l,int r)
{
ans=(2*ans-C(l,r)+MOD)%MOD;
}
inline void update2(int l,int r)
{
ans=((ans+C(l,r))%MOD)*two%MOD;
}
inline void update3(int l,int r)
{
ans=(ans-C(l,r)+MOD)%MOD;
}
inline void update4(int l,int r)
{
ans=(ans+C(l,r))%MOD;
}
inline void solve()
{
int i,l,r;
l=1;r=0;
ans=1;
for(i=1;i<=m;i++)
{
while(l<q[i].l) update1(l,r),l++; //将l向右移至q[i].l
while(l>q[i].l) update2(l-1,r),l--; //将l向左移至q[i].l
while(r>q[i].r) update3(l,r),r--; //将r左移至q[i].r
while(r<q[i].r) update4(l,r+1),r++; //将r右移至q[i].r
res[q[i].id]=ans;
}
}
void init()
{
ll p=1;
jc[0]=1;
jc[1]=1;
inv[0]=1;
inv[1]=1;
for(int i=2;i<MAXN;i++)
{
p=(p*i)%MOD;
jc[i]=p;
//inv[i]=inv[MOD%i]*(MOD-MOD/i)%MOD;
}
for(int i=2;i<MAXN;i++) inv[i]=inv[MOD%i]*(MOD-MOD/i)%MOD; //O(n)求逆元
for(int i=2;i<MAXN;i++) inv[i]=inv[i-1]*inv[i]%MOD; //扩展到i!的逆元
}
int main()
{
int k;
init();
two=inv[2];
scanf("%d",&m);
n=100000;
for(int i=1;i<=m;i++)
{
scanf("%d%d",&q[i].l,&q[i].r);
//q[i].ans=-1;
q[i].id=i;
//pos[q[i].l]=q[i].l/block;
}
int block=sqrt(n);
for(int i=1;i<=m;i++)
if(pos[q[i].l]==0)
pos[q[i].l]=(q[i].l/block)+1;
sort(q+1,q+m+1,cmp); //按照块来排序
solve();
//sort(q+1,q+m+1,cmp1);
for(int i=1;i<=m;i++)
{
printf("%d\n",res[i]);
}
return 0;
}