HDU 6333 Harvest of Apples (组合数+逆元+莫队)

题目传送门

题目意思很简单,就是求C(n,0)~C(n,m)的和。但是暴力算肯定会超时,所以得用神奇的方法写,这样我们就引出了莫队的方法。
在这里插入图片描述
我们设前缀和S(n,m)=C(n,0)+…+C(n,m);由于莫队需要记录当前状态,所以不难推出以下四个式子:
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
然后快乐莫队就行!

注意:

  1. 最后一个千万别写除以二!!要写乘以2的逆元!!!血的教训!!!
  2. 注意数据范围,该开long long得开,并且组合数需要用特殊方法求,否则精度会炸!!!
  3. 仔细+仔细!
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+100;
const long long MOD=1e9+7;
long long a[maxn];
long long ans[maxn];
long long F[maxn], Finv[maxn], inv[maxn];
int step;
struct node{
	int l,r,pos;
}s[maxn];
bool cmp(node x,node y){
	return x.r/step==y.r/step?x.l<y.l:x.r<y.r;
}
//求组合数
long long comb(int n, int m){
    if(m > n) return 0;
    return F[n]*1ll*Finv[n - m]%MOD*Finv[m]%MOD;
}
int main(){
//逆元板子
	inv[1]=1;
    for(int i=2;i<maxn;i++){
        inv[i]=(MOD-MOD/i)*1ll*inv[MOD % i]%MOD;
    }
    F[0]=Finv[0]=1;
    for(int i=1;i<maxn;i++){
        F[i]=F[i-1]*1ll*i%MOD;
        Finv[i]=Finv[i-1]*1ll*inv[i]%MOD;
    }
	int T;
	cin>>T;
	int n=0;
	for (int i=1;i<=T;i++){
		cin>>s[i].r>>s[i].l;
		if (n<s[i].r) n=s[i].r;
		s[i].pos=i;
	}
		step=sqrt(n);
		sort(s+1,s+1+T,cmp);
//莫队	
	int i=1;
	long long l=1,r=0,now=1;
	long long tt;
	while (i<=T){
		while (r<s[i].r){
			tt=(now+now)%MOD; 
			now=(tt-comb(r,l)+MOD)%MOD;
			r++;
		}
		while (r>s[i].r){
			tt=(now+comb(r-1,l))%MOD;
			now=(tt*inv[2])%MOD;
			r--;
		}
		while (l<s[i].l){
			now=(now+comb(r,l+1))%MOD;
			l++;
		} 
		while (l>s[i].l){
			now=(now-comb(r,l)+MOD)%MOD;
			l--;
		}
		ans[s[i].pos]=now;
		i++;
	}
	for (int j=1;j<=T;j++){
		cout<<ans[j]%MOD<<endl;
	}
	return 0;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值