http://acm.hdu.edu.cn/showproblem.php?pid=6333
题意:
每次给你一个n和m,让你求。
询问有1e5次,n,m<=1e5。
POINT:
把要所求的式子变为f(n,m)。可得:
f(n+1,m)=2*f(n,m)-C(n,m)
f(n,m+1)=f(n,m)+C(n,m+1).
这样,上下左右的递推公式便有了。就可以用莫队算法了。
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <algorithm>
#include <queue>
#include <cmath>
using namespace std;
#define LL long long
const LL N = 1e5+55;
const LL M = 1e5+5;
const LL inf = 0x3f3f3f3f;
const LL MOD = 1e9+7;
LL a[N],Fac[N],Inv[N];
struct node
{
LL l,r;
LL id;
LL ans;
}q[M];
LL bk[N];
bool cmp(node a,node b)
{
if(bk[a.l]!=bk[b.l])
return bk[a.l]<bk[b.l];
else
return a.r<b.r;
}
bool CMP(node a,node b)
{
return a.id<b.id;
}
LL pow_mod(LL base,LL mi)
{
LL ans=1;
while(mi){
if(mi&1) ans=ans*base%MOD;
base=base*base%MOD;
mi>>=1;
}
return ans;
}
LL C(LL n,LL m)
{
if(m>n) return 0;
return Fac[n]*Inv[n-m]%MOD*Inv[m]%MOD;
}
void init()
{
Fac[0] = 1;
for (LL i = 1; i <= N; i++) Fac[i] = (Fac[i-1] * i) % MOD;
Inv[N] = pow_mod(Fac[N], MOD-2);
for (LL i = N - 1; i >= 0; i--) Inv[i] = Inv[i+1] * (i + 1) % MOD;
}
int main()
{
init();
LL block=sqrt(1e5);
for(LL i=1;i<=1e5;i++) bk[i]=(i-1)/block;
LL n;scanf("%lld",&n);
for(LL i=1;i<=n;i++){
scanf("%lld%lld",&q[i].l,&q[i].r);
q[i].id=i;
}
sort(q+1,q+1+n,cmp);
LL l=1,r=1,ans=2;
for(LL i=1;i<=n;i++){
while(l<q[i].l){
ans=(2*ans-C(l,r)+MOD)%MOD;
l++;
}
while(l>q[i].l){
l--;
ans=(ans+C(l,r))*Inv[2]%MOD;
}
while(r<q[i].r){
r++;
ans=(ans+C(l,r))%MOD;
}
while(r>q[i].r){
ans=(ans-C(l,r)+MOD)%MOD;
r--;
}
q[i].ans=ans;
}
sort(q+1,q+1+n,CMP);
for(int i=1;i<=n;i++)
printf("%lld\n",q[i].ans);
return 0;
}