HDU 6333 多校第四场1002

题意:计算C(n,0)~C(n,m)的和  ,文中我们用S(n,m)表示

题解给的莫队做法,也就是说我们可以从一个S(n,m) 可以知道S(n - 1,m)、S(n + 1,m)、S(n,m - 1)、S(n,m + 1),如果可以实现这个的话,我们就可以用莫队算法,现在我们来推导一下

S(n,m) = C(n,0) + C(n,1) + C(n,2) +...... + C(n,m - 1) + C(n,m)

从上式中我们不难看出S(n,m) = S(n,m - 1) + C(n,m),因为S(n,m - 1) = C(n,0) + C(n,1) + C(n,2) +...... + C(n,m - 1)

ok!我们从这个式子中我们就可以完成S(n,m)变成S(n,m - 1)或者S(n,m + 1)这两种情况

也就是S(n,m - 1) = S(n,m) - C(n,m),S(n,m + 1) = S(n,m) + C(n,m + 1)

接着我们根据组合数的递推公式C(n,m) = C(n - 1,m) + C(n - 1,m - 1)我们可以推出

S(n,m) = C(n,0) + C(n,1) + C(n,2) +...... + C(n,m)

S(n,m) = C(n - 1,0) + (C(n - 1,1) + C(n - 1,0))+ (C(n - 1,2) + C(n-1,1)) +...... + (C(n - 1,m) + C(n - 1,m - 1))

我们整理一下

S(n,m) = 2 * (C(n - 1,0) + C(n - 1,1) + C(n - 1,2) + ....... + C(n - 1,m - 1)) + C(n - 1,m)

S(n,m) = 2 * S(n-1,m) - C(n - 1,m)

ok!我们从这个式子中我们就可以完成S(n,m)变成S(n - 1,m)或者S(n + 1,m)这两种情况

也就是S(n - 1,m) = (S(n,m) + C(n - 1,m)) / 2,S(n + 1,m) = 2 * S(n,m) - C(n,m)

综上整理:

①S(n,m - 1) = S(n,m) - C(n,m)

②S(n,m + 1) = S(n,m) + C(n,m + 1)

③S(n - 1,m) = (S(n,m) + C(n - 1,m)) / 2

④S(n + 1,m) = 2 * S(n,m) - C(n,m)

这样我们就完成了因为题目给的n,m为1e5所以计算C(n,m)时要预先处理好否者会TLE

剩下的就是套一个莫队算法就可以了,离线输出答案

代码:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define INF 0x3f3f3f3f
#define maxn 100005
#define maxnn 6000
#define juzheng 300
#define line cout << "-------------------------" << endl;
#define PI acos(-1.0)
#define mem(a,b) memset(a,b,sizeof(a))
#define fill_(a,b,n) fill(a,a + n,b)
#define esp 1e-9
 
#define ri(n) scanf("%d",&n)
#define ri2(a,b) scanf("%d %d",&a,&b)
#define ri3(a,b,c) scanf("%d %d %d",&a,&b,&c)
#define rd(n) scanf("%lf",&n)
#define rd2(a,b) scanf("%lf %lf",&a,&b)
#define rd3(a,b,c) scanf("%lf %lf %lf",&a,&b,&c)
#define rl(n) scanf("%lld",&n)
#define rl2(a,b) scanf("%lld %lld",&a,&b)
#define rl3(a,b,c) scanf("%lld %lld %lld",&a,&b,&c)
#define rs(str) scanf("%s",str)
#define pr(n) cout << n << endl
#define ll long long
#define int64 __int64
 
using namespace std;
 
//Date:2018-8-1
//Author:HarryBlackCat
 
ll fac[maxn],inv[maxn],inv2;
 
const ll mod = 1e9 + 7;
 
const ll MAXN = 1e5 + 5;
const ll MAXM = 1e5 + 5;
struct Query {
	ll L,R,id;
} node[MAXM];
 
ll a[MAXM],num[MAXN],m,unit,ans[maxn];
 
ll C(int n,int k) {//求组合数 
	return fac[n] * inv[k] % mod * inv[n - k] % mod;
}
 
bool cmp(Query a,Query b) {
	if(a.L / unit != b.L / unit)
		return a.L / unit < b.L / unit;
	else
		return a.R < b.R;
}
 
void work() {
	ll temp = 2;//最少的时候苹果为1,有2种情况
	memset(num,0,sizeof(num));
	ll L = 1,R = 1;
	for(ll i = 0; i < m; i++) {
		while(L < node[i].L) {//这里是N++ 
			temp = (2 * temp % mod - C(L,R) + mod) % mod;
			L++;
		}
		
		while(R < node[i].R) {//这里是M++ 
			R++;
			temp = (temp + C(L,R)) % mod;
		}
 
 
		while(L > node[i].L) {//这里是N-- 
			L--;
			temp = (temp + C(L,R)) % mod * inv2 % mod;
		}
		
		while(R > node[i].R) {//这里是M-- 
			temp = (temp - C(L,R) + mod) % mod; 
			R--;
		}
 
		ans[node[i].id] = temp;
	}
}
 
void mo_init() {
	unit = (ll)sqrt(maxn);
}
 
ll quickpow(ll a,ll b) {
	ll ans=1;
	while(b) {
		if(b&1) {
			ans=(ans*a)%mod;
		}
		a=(a*a)%mod;
		b>>=1;
	}
	return ans;
}
 
ll get_inv(ll x,ll MOD) {
	return quickpow(x,MOD - 2);
}
 
void init() {
	fac[0] = fac[1] = 1;
	for(int i = 2; i < maxn; i++)
		fac[i] = i * fac[i - 1] % mod;//预处理阶乘
	inv[maxn - 1] = get_inv(fac[maxn - 1],mod);//预处理逆原
	for(int i = maxn - 2; i >= 0; i--)
		inv[i] = inv[i + 1] * (i + 1) % mod;//逆原递推
	mo_init();
	inv2 = get_inv(2,mod);
}
 
int main() {
	//cin.sync_with_stdio(false);//降低cin,cout时间
	init();
 
	int t;
	while(~ri(t)) {
		int Case = 0;
		while(t--) {
			ri2(node[Case].L,node[Case].R);
			node[Case].id = Case;
			Case++;
		}
 
		sort(node,node + Case,cmp);
 
		m = Case;
		work();
		
		for(int i = 0;i < Case;i++){
			printf("%lld\n",ans[i]);
		}
			
	}
	return 0;
}

 

你可能感兴趣的:(HDU 6333 多校第四场1002)