[NOIP2016提高組]組合數問題
阿新 • • 發佈:2017-09-14
() -a printf ++ 提高 urn 數論 tro ont
題目:UOJ#263、洛谷P2822、Vijos P2006、codevs5947。
題目大意:t組數據,每次給你n和m$\leq 2000$,求對於所有的$(0\leq i\leq n)$,$(0\leq j\leq m)$的(i,j),有多少對滿足$C^j_i\equiv 0(mod\ k)$。
解題思路:此題是一道數論題。首先,組合數有一個遞推公式:$C^m_n=C^m_{n-1}+C^{m-1}_n$,這其實和楊輝三角的遞推公式是一樣的。那麽我們可以預處理出所有的組合數,然後對於每一個問題,都從組合數裏找滿足條件的數。但由於$(t\leq 10^4)$,這樣做會超時。
我們可以用二維前綴和的思路,求遞推組合數的同時,把滿足條件的數記錄下來,然後每次詢問的時間復雜度就是$O(1)$。具體見代碼。
註意求組合數要邊加邊模k,否則可能會爆。
時間復雜度$O(\sum\limits_{i=1}^{2000}i)$。
C++ Code:
#include<cstdio> using namespace std; int ans[2002][2002],t,k,C[2002][2002]; int main(){ scanf("%d%d",&t,&k); C[1][1]=C[2][1]=C[2][2]=1; ans[1][1]=ans[1][2]=ans[2][2]=0; for(int i=3;i<=2000;++i){ C[i][1]=C[i][i]=1; ans[i][1]=0; for(int j=2;j<i;++j){ C[i][j]=(C[i-1][j]+C[i-1][j-1])%k; ans[i][j]=ans[i][j-1]+ans[i-1][j]-ans[i-1][j-1]; if(C[i][j]==0)++ans[i][j]; } ans[i][i]=ans[i][i-1]; } while(t--){ int n,m; scanf("%d%d",&n,&m); if(n<m)m=n; printf("%d\n",ans[n+1][m+1]); } return 0; }
[NOIP2016提高組]組合數問題