题干:
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 ;
}