题链:https://vjudge.net/problem/HDU-6333
题意:给出n,m,求。
思路:首先,题目保证m<=n,我们考虑把m看成l,n看成r。那么,问题就转化为了莫队解决的区间问题。首先我们定义 。
现在考虑添加删除操作。对于l的移动我们可以轻松的解决。
当l<ql时,
当l>ql时,
但是对于r的移动,我们就要推一下了,我们知道组合公式可以根据杨辉三角计算,。
那么我们现在解决r的移动了。
当r<qr时,
当r>qr时,
我们都知道阶乘可以的时间通过递推式
来推出,其实在数论中阶乘的逆元也是可以用递推式
来推出的,稍微证明一下:
我们设
的逆元表示为
,现在我们要求
的逆元,我们可以考虑将
乘上一个
变为
得证
注意:
1、
2、初值l=1 , r=1 ; sum=2。
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const ll mod = 1e9+7;
const int N = 1e5+10;
ll f[N],in[N],in2,ans[N],sum;
struct node{
int l,r,id;
}q[N];
int n,block,be[N];
ll poww(ll a, ll b){
ll ans=1;
while(b){
if(b&1) ans=(ans*a)%mod;
a=(a*a)%mod;
b>>=1;
}
return ans;
}
bool cmp(node a,node b){
return (be[a.l]^be[b.l]) ? be[a.l]<be[b.l] : (be[a.l]&1) ? a.r<b.r : a.r>b.r;
}
ll C(int n,int m){
return n<m ? 0LL : f[n]*in[m]%mod*in[n-m]%mod;
}
int main(void){
block=ceil(sqrt(N));
in[0]=f[0]=1;
for(int i=1;i<N;i++)
f[i]=f[i-1]*i%mod,be[i]=i/block;
in[N-1]=poww(f[N-1],mod-2);
in2=poww(2LL,mod-2);
for(int i=N-2;i>=1;i--)
in[i]=in[i+1]*(i+1)%mod;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d%d",&q[i].r,&q[i].l),q[i].id=i;
sort(q+1,q+1+n,cmp);
int l=1,r=1;
sum=2;
for(int i=1;i<=n;i++){
int ql=q[i].l,qr=q[i].r;
while(l<ql) sum=(sum+C(r,++l))%mod;
while(l>ql) sum=(sum-C(r,l--)+mod)%mod;
while(r<qr) sum=(2*sum%mod-C(r++,l)+mod)%mod;
while(r>qr) sum=((sum+C(--r,l))%mod*in2)%mod;
ans[q[i].id]=sum;
}
for(int i=1;i<=n;i++)
printf("%lld\n",ans[i]);
return 0;
}