*【HDU - 6333】Problem B. Harvest of Apples (莫队,逆元,组合数学)(这样预处理正确吗?)

题干:

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了)然而超时了。

   正解是这样的,(链接)首先我们要知道组合数和杨辉三角存在着密切的关系?(貌似是高中讲二项式定理的时候提到的)
S(m,n)表示n个苹果最多取m个的方案数,很容易想到S(m,n)=S(m-1,n)+C_{n}^{m}

根据杨辉三角也很容易推出S(m,n)=2*S(m,n-1)- C_{n-1}^{m}

我们将m~n当作一条线段,那么S(m,n)就是这条线段的函数值,而根据上面的两个公式,又可以在O(1)的时间内实现S(m,n)S(m-1,n)S(m+1,n)S(m,n-1)S(m,n+1)的转移。利用莫队算法离线处理即可。

AC代码:

#include
#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.lb.r;
	return a.r>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 ;
}

 

你可能感兴趣的:(莫队算法,组合数学,数论,HDU)