HDU 6333 Harvest of Apples 組合數求和,莫隊
阿新 • • 發佈:2018-11-02
題意:Q次詢問,每次給出(n,m)問 S(n,m)=C(n,0)+C(n,1)+C(n,2)+...C(n,m).
1<=Q,m<=n<=1e5
S(n,m)=S(n,m-1)+C(n,m) . S(n,m)=2*S(n-1,m)-C(n,m).
預處理階乘和階乘的逆元以後, 可以從一個詢問S(n,m) O(1)轉移到S(n+1,m),S(n-1,m),S(n,m+1),S(n,m-1).
然後就可以跑一遍莫隊即可.
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N=1e5+5,mod=1e9+7; struct node{ int l,r,id; }q[N]; int pos[N],Q; ll ans[N],res,f[N],inv[N]; ll powmod(ll x,ll n){ ll s=1; while(n){ if(n&1) s=(s*x)%mod; n>>=1; x=(x*x)%mod; } return s; } void init(){ res=2; int block=sqrt(N); f[0]=inv[0]=inv[1]=1; for(int i=1;i<N;i++){ pos[i]=(i-1)/block+1; f[i]=(f[i-1]*1ll*i)%mod; } inv[N-1]=powmod(f[N-1],mod-2); for(int i=N-2;i>1;i--) inv[i]=inv[i+1]*(i+1)%mod; } bool cmp(node a,node b){ if(pos[a.l]==pos[b.l]) return a.r<b.r; return a.l<b.l; } ll C(int n,int m){ ll comb=(f[n]*inv[n-m])%mod; comb=(comb*inv[m])%mod; return comb; } void solve(){ ll dv2=powmod(2,mod-2); for(int i=0,l=1,r=1;i<Q;i++){ for(;r<q[i].r;r++) res=(2ll*res-C(r,l)+mod)%mod; for(;r>q[i].r;r--) res=(((res+C(r-1,l))%mod)*dv2)%mod; for(;l<q[i].l;l++) res=(res+C(r,l+1))%mod; for(;l>q[i].l;l--) res=(res-C(r,l)+mod)%mod; ans[q[i].id]=res; } } int main(){ ios::sync_with_stdio(false); cin.tie(0); init(); cin>>Q; for(int i=0;i<Q;i++) cin>>q[i].r>>q[i].l,q[i].id=i; sort(q,q+Q,cmp); solve(); for(int i=0;i<Q;i++) cout<<ans[i]<<'\n'; return 0; }