原题:hdu 6335
题意:
给n,m,输出S(n,m): C(n,0)+…C(n,m)
解析:
遇到阶乘的时候我是很开心的,因为我可以直接预处理阶乘和逆元,感觉无敌了,然而数据太大TLE了
首先有一个阶乘转换的公式:C(n,m)==C(n-1,m)+C(n-1,m-1),证明我就不写了,直接展开就可以推出来了
C(n,m)==C(n-1,m)+C(n-1,m-1) ;
C(n,m-1)==C(n-1,m-1)+C(n-1,m-2) ;
…
C(n,2)==C(n-1,2)+C(n-1,1) ;
C(n,1)==C(n-1,1)+C(n-1,0) ;
C(n,0)==C(n-1,0)
–>S(n,m)=2*S(n-1,m)-C(n-1,m)
就是说S(n,m)和S(n-1,m)可以直接转化,而且我们知道S(n,m)和S(n,m-1)也可以直接转换,so,我们可以在做出一个询问的答案后,想办法利用前面的这个答案来推出之后的答案
这个时候,有一个很符合题意的算法,莫队…(这里就不讲了,博客里有)
代码:
D read(){ D ans=0; char last=' ',ch=getchar();
while(ch<'0' || ch>'9')last=ch,ch=getchar();
while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
if(last=='-')ans=-ans; return ans;
}
const int N=100009;
D swift(D a,D b){
D ans=1ll;
while(b){
if(b%2)ans=ans*a%mod;
b>>=1;
a=a*a%mod;
}return ans;
}
//阶乘初始化
D fac[N];
D inv_fac[100007];
void init(){
fac[1]=1;
for(D i=2;i<=100000;i++)fac[i]=fac[i-1]*i%mod;//初始化阶乘
inv_fac[100000]=swift(fac[100000],mod-2);//费马小定理求 1000!的逆元
for(D i=99999;i>=1;i--)
inv_fac[i]=(inv_fac[i+1]*(i+1))%mod; //预处理 i!的逆元
}
D C(D a,D b){//组合数 a下
if(b>a||b<0)return 0;
if(b==0||a==b)return 1;
return fac[a]*inv_fac[b]%mod*inv_fac[a-b]%mod;
}
D k=(D)sqrt(100000);
struct node {
D l,r;int id;
bool operator<(const node a)const{
if(l/k!=a.l/k)return l/k<a.l/k;
return r<a.r;
}
}e[100009];
D ans[100009];
int main(){
init();
int t=read();
for(int i=1;i<=t;i++){
e[i].id=i,e[i].r=read(),e[i].l=read();
}
sort(e+1,e+1+t);
//D l=e[1].l,r=e[1].r;
D l=0,r=1;
D now=1;
for(int i=1;i<=t;i++){
while(e[i].r>r)now=(2*now-C(r,l)+mod)%mod,r++;//S(r,l)->S(r+1,l)
while(e[i].l<l)now=(now+mod-C(r,l))%mod,l--;//S(r,l)->S(r,l-1)
while(e[i].r<r)now=((now+C(r-1,l))*500000004%mod),r--;//S(r,l)->S(r-1,l)
while(e[i].l>l)now=(now+mod+C(r,l+1))%mod,l++;//S(r,l)->S(r,l+1)
ans[e[i].id]=now;
}
for(int i=1;i<=t;i++){
printf("%lld\n",ans[i]);
}
}