1. 程式人生 > >[NOIP2016提高組]組合數問題

[NOIP2016提高組]組合數問題

() -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提高組]組合數問題