题干:
There are nn apples on a tree, numbered from 11 to nn.
Count the number of ways to pick at most mm apples.
Input
The first line of the input contains an integer TT (1≤T≤105)(1≤T≤105) denoting the number of test cases.
Each test case consists of one line with two integers n,mn,m (1≤m≤n≤105)(1≤m≤n≤105).
Output
For each test case, print an integer representing the number of ways modulo 109+7109+7.
Sample Input
2
5 2
1000 500
Sample Output
16
924129523
解题报告:
不得不说,一道好题。
会者不难,难者不会。
刚开始想到离线了。这么想的:想着组合数公式打表,但是空间复杂度不容许,然后像滚动数组优化,自然而然就想到离线了,这样跑下来就相当于是求了一遍1e5的组合数。(相当于n^2了)然而超时了。
正解是这样的,(链接)首先我们要知道组合数和杨辉三角存在着密切的关系?(貌似是高中讲二项式定理的时候提到的)
令表示n个苹果最多取m个的方案数,很容易想到
根据杨辉三角也很容易推出
我们将m~n当作一条线段,那么就是这条线段的函数值,而根据上面的两个公式,又可以在O(1)的时间内实现到、、、的转移。利用莫队算法离线处理即可。
AC代码:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int MAX = 1e5 + 5;
const ll mod = 1000000007;
ll jie[MAX],inv[MAX],q[MAX];
struct Node {
int l , r,block,id;
} node[MAX];
//bool cmp(Node a,Node b) {
// if(a.block == b.block) return a.r < b.r;
// else return a.l < b.l;
//}
//这样分块貌似会快不少?
bool cmp(Node a,Node 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;
}
//这个c函数是错的。。。貌似就是因为没有判断r<l的情况?
//ll c(ll n,ll m) {
// return jie[n]*(jie[m]%mod*jie[n-m]%mod);
//}
ll c(int r,int l) {
if (r<l) return 0;
return jie[r]*inv[l]%mod*inv[r-l]%mod;
}
int main()
{
jie[1] = 1;jie[0] = 1;
inv[1] = 1;inv[0] = 1;
for(int i = 2; i<=MAX-1; i++) jie[i] = (jie[i-1] * i)%mod;
for(int i = 2; i<=MAX-1; i++) {
inv[i] = (mod - mod/i*inv[mod%i]%mod)%mod;
}
//这两个求逆元的公式都可以使用
// for (int i=2; i<MAX; i++) {
// inv[i]=inv[mod%i]*(mod-mod/i)%mod;
// }
//预处理逆元的前缀积
for (int i=2; i<MAX; i++) inv[i]=inv[i-1]*inv[i]% mod;
int t;
cin>>t;
int blk = sqrt(100000);
for(int i = 1; i<=t; i++) {
scanf("%d%d",&node[i].r,&node[i].l);
node[i].id = i;
node[i].block = node[i].l/blk;
}
int l=1,r=1;
ll ans = 2;
sort(node+1,node+t+1,cmp);
for(int i = 1; i<=t; i++) {
while(l < node[i].l) l++,ans = (ans + c(r,l))%mod;
while(l > node[i].l) ans = (ans - c(r,l) + mod) % mod,l--;
while(r < node[i].r) r++,ans = (2*ans-c(r-1,l) + mod )%mod;
while(r > node[i].r) ans = (ans + c(r-1,l)) * inv[2] % mod,r--;
q[node[i].id] = ans;
}
for(int i = 1; i<=t; i++) printf("%lld\n",q[i]);
return 0 ;
}