HDU - 6333 Problem B. Harvest of Apples(莫队变形+思维+组合数学,好题)
題目鏈接:點擊查看
題目大意:給出n個蘋果樹,每個蘋果樹上可以摘一個蘋果,問摘不超過m個蘋果有多少種方式
題目分析:首先根據題意和樣例可以推出,答案就是一個組合數之和,設C(n,m)為從n個數中選m個數的方案數,再設S(n,m)為本題答案數,則有S(n,m)=C(n,0)+C(n,1)+....+C(n,m-1)+C(n,m),因為樣例組數給到了1e5,所以我們肯定不能暴力去計算每一個值n的答案,于是這個題目就需要離線處理,又因為題目中的m一定小于等于n,所以我們不妨將n和m視為區間,則[n,m]就可以視為[l,r]了,很自然的就轉換成了莫隊問題。現在我們的問題就是要解決add函數和del函數,但這個題目比較特殊,我們先一步一步來推一下。通過上面答案S(n,m)的定義式,不難看出遞推式就是S(n,m)=S(n,m-1)+C(n,m),這是其中的一個條件,再就是根據楊輝三角形可以得出組合數的遞推公式之二C(n,m)=C(n-1,m-1)+C(n-1,m),那么答案繼續對答案S(n,m)的定義式變形:
S(n,m)
=C(n,0)+C(n,1)+....+C(n,m-1)+C(n,m)
=[0+C(n-1,0)]+[C(n-1,0)+C(n-1,1)]+..+[C(n-1,m-2)+C(n-1,m-1)]+[C(n-1,m-1)+C(n-1,m)]
=2*S(n-1,m)-C(n-1,m)
到此為止,現在我們可以整理出四個遞推式了:
根據初始的兩個遞推式和答案的定義式,就可以推出上面四個關鍵的公式了
然后再根據組合數的公式:,可以預處理出所有的階乘和階乘的逆元,然后O(1)求出每個組合數了
這里稍微補充一個知識,我們都知道階乘可以O(n)的時間通過遞推式fac[i]=fac[i-1]*i來推出,其實在數論中階乘的逆元也是可以同歸遞推式inv[i]=inv[i+1]*(i+1)來推出的,稍微證明一下:
我們設的逆元表示為,現在我們要求的逆元,我們可以考慮將乘上一個變為
則根據前提滿足關系:
即
得證inv[i]=inv[i+1]*(i+1)
預處理完上面的東西后,再根據公式改寫一下莫隊的模板就好了,還有需要注意的幾個地方是:
代碼:
#include<iostream> #include<cstdlib> #include<string> #include<cstring> #include<cstdio> #include<algorithm> #include<climits> #include<cmath> #include<cctype> #include<stack> #include<queue> #include<list> #include<vector> #include<set> #include<map> #include<sstream> #include<unordered_map> using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const int N=1e5+100;const int mod=1e9+7;int size,m;LL ans[N],fac[N],inv[N];struct query {int l,r,id;bool operator<(const query& a)const{if(l/size!=a.l/size)return l<a.l;else if((l/size)&1)return r<a.r;elsereturn r>a.r;} }q[N];LL q_pow(LL a,LL b) {LL ans=1;while(b){if(b&1)ans=ans*a%mod;a=a*a%mod;b>>=1;}return ans; }LL C(int n,int m)//求組合數,n個里面選m個 {if(n<m)return 0;return fac[n]*inv[m]%mod*inv[n-m]%mod; }void solve() {int l=0,r=1;LL sum=1;for(int i=1;i<=m;i++){int ql=q[i].l;int qr=q[i].r;while(l<ql)//日常模一模防爆sum=(sum+C(r,++l))%mod;while(l>ql)sum=(sum+mod-C(r,l--))%mod;while(r<qr)sum=(sum*2%mod+mod-C(r++,l))%mod;while(r>qr)sum=(sum+C(--r,l))%mod*inv[2]%mod; ans[q[i].id]=sum;} }void init() {size=sqrt(1e5);fac[0]=1;for(int i=1;i<N;i++)fac[i]=fac[i-1]*i%mod;inv[N-1]=q_pow(fac[N-1],mod-2);for(int i=N-2;i>=0;i--)inv[i]=inv[i+1]*(i+1)%mod; }int main() { // freopen("input.txt","r",stdin); // ios::sync_with_stdio(false);init();scanf("%d",&m);for(int i=1;i<=m;i++){scanf("%d%d",&q[i].r,&q[i].l);q[i].id=i;}sort(q+1,q+1+m);solve();for(int i=1;i<=m;i++)printf("%lld\n",ans[i]);return 0; }?
總結
以上是生活随笔為你收集整理的HDU - 6333 Problem B. Harvest of Apples(莫队变形+思维+组合数学,好题)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CodeForces - 1109A S
- 下一篇: CodeForces - 1168B G