题目意思很简单,就是求C(n,0)~C(n,m)的和。但是暴力算肯定会超时,所以得用神奇的方法写,这样我们就引出了莫队的方法。
我们设前缀和S(n,m)=C(n,0)+…+C(n,m);由于莫队需要记录当前状态,所以不难推出以下四个式子:
然后快乐莫队就行!
注意:
- 最后一个千万别写除以二!!要写乘以2的逆元!!!血的教训!!!
- 注意数据范围,该开long long得开,并且组合数需要用特殊方法求,否则精度会炸!!!
- 仔细+仔细!
#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;
}