- 可以看出,从\((n,m)\)的状态转移到\((n+1,m)\),\((n,m+1)\),\((n-1,m)\),\((n,m-1)\)都是比较容易的,可以直接\(O(1)\)转移。
有以下式子:
\[S_{n}^{m+1}=S_{n}^{m}+C_{n}^{m+1}
\]
\[S_{n}^{m-1}=S_{n}^{m}-C_{n}^{m}
\]
\[S_{n+1}^{m}=S_{n}^{m}*2-C_{n}^{m}
\]
\[S_{n-1}^{m}=\frac{S_{n}^{m}+C_{n-1}^{m}}{2}
\]
然后根据这些式子加上莫队的板子即可。
把\(r\)设为\(n\),\(l\)看作\(m\),然后在指针移动的时候,按照上面式子转移即可。
记得用线性求逆元,另外在求组合数的时候记得要判\(a<b:return 0\)
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define int long long
using namespace std;
const int maxn=1e5+1,maxnn=1e5+1;
const int mod=1e9+7;
int ID;
int belong[maxn];
int ans[maxn];
int fac[maxn];
int n,Max=0;
int inv[maxnn],invv[maxn];
struct E{int l,r,id;}q[maxn];
void Pre(){
fac[1]=1;
for(int i=2;i<=1e5;i++)fac[i]=fac[i-1]*i%mod;
inv[1]=invv[1]=inv[0]=invv[0]=1;
for(int i=2;i<=1e5;i++)invv[i]=mod-mod/i*invv[mod%i]%mod,inv[i]=inv[i-1]*invv[i]%mod;
}
int Fp(int b,int p){
int res=1;
while(p){
if(p&1)res=res*b%mod;
p>>=1;b=b*b%mod;
}return res;
}
int Comb(int a,int b){
if(a<b)return 0;
if(a==b||b==0)return 1;
return (fac[a]*inv[b]%mod)*inv[a-b]%mod;
}
bool Cmp(E a,E b){
return (belong[a.l]^belong[b.l]) ? belong[a.l] < belong[b.l] : ((belong[a.l] & 1) ? a.r < b.r : a.r > b.r);
}
signed main(){
freopen("sum.in","r",stdin);
freopen("sum.out","w",stdout);
scanf("%lld",&ID);
scanf("%lld",&n);
Pre();
for(int i=1;i<=n;i++){
scanf("%lld%lld",&q[i].r,&q[i].l);
q[i].id=i;
Max=max(Max,q[i].r);
}
int sz=sqrt(Max);
int bnum=ceil((double)n/sz);
for(int i=1;i<=bnum;++i){
for(int j=(i-1)*sz+1;j<=i*sz;++j){
belong[j]=i;
}
}
sort(q+1,q+n+1,Cmp);
int ANS=2;
int l=1,r=1;
for(int i=1;i<=n;i++){
int ql=q[i].l,qr=q[i].r;
while(l<ql){ANS=(ANS+Comb(r,++l))%mod;}
while(l>ql){ANS=(ANS-Comb(r,l--)+mod)%mod;}
while(r<qr){ANS=(ANS*2%mod-Comb(r++,l)+mod)%mod;}
while(r>qr){ANS=((ANS+Comb(--r,l)))%mod*invv[2]%mod;}
ans[q[i].id]=ANS%mod;
}for(int i=1;i<=n;i++){
printf("%lld\n",ans[i]);
}
return 0;
}