http://acm.hdu.edu.cn/showproblem.php?pid=6333
题意:求c(n,0)到c(n,m)的和t组数据
每次累加一定会超时
得到公式s(n,m)=s(n-1,m)-c(n-1,m);
用莫队算法处理t组查询
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#define LL long long
using namespace std;
const int mod=1e9+7;
struct node
{
LL l,r;
int id;
} a[100003];
LL pp=500;//分块
int t;
LL fac[100003],inv[100003];//fac阶乘,inv阶乘的逆元
LL ans[100003];//答案
LL num=1,p;//p是2的逆元
bool cmp(node x,node y)//排序
{
LL xl=x.l/pp;
LL yl=y.l/pp;
if(xl==yl)//在一个块
return x.r<y.r;
return xl<yl;
}
LL qpow(LL a,LL b)//阶乘的逆元
{
LL res=1;
while(b)
{
if(b&1)
res=(res*a)%mod;
a=a*a%mod;
b/=2;
}
return res;
}
void modui()//莫队算法
{
int n=1,m=0;
for(int i=0; i<t; i++)
{
while(n<a[i].l)
{
num=(2*num%mod-fac[n]*inv[m]%mod*inv[n-m]%mod+mod)%mod;//减得时候先加一个mod再取余防止是负数
n++;
}
while(m<a[i].r)
{
num=(num+fac[n]*inv[m+1]%mod*inv[n-1-m]%mod)%mod;
m++;
}
while(m>a[i].r)
{
num=(num-fac[n]*inv[m]%mod*inv[n-m]%mod+mod)%mod;//减得时候先加一个mod再取余防止是负数
m--;
}
while(n>a[i].l)
{
num=(num+fac[n-1]*inv[m]%mod*inv[n-1-m]%mod)*p%mod;
n--;
}
ans[a[i].id]=num%mod;
}
}
int main()
{
scanf("%d",&t);
for(int i=0; i<t; i++)
{
scanf("%lld%lld",&a[i].l,&a[i].r);
a[i].id=i;
}
sort(a,a+t,cmp);
fac[0]=1,inv[0]=1;//这个地方很重要
for(int i=1; i<=100000; i++)
{
fac[i]=fac[i-1]*i%mod;
}
int mx=100000;
p=qpow(2,mod-2);
for(int i=100000;i>=1;i--)
{
inv[i]=qpow(fac[i],mod-2);
}
modui();
for(int i=0; i<t; i++)
{
printf("%lld\n",ans[i]);
}
}