1. 程式人生 > >2016 組合數問題

2016 組合數問題

組合數問題

題面

在這裡插入圖片描述
對,就是這樣這樣的一道題,卡了博主好多天,emmmm,反正最後是看題解ac的……(是吧,我也感覺自己好弱)
首先,上一份自己看的題解,強烈推薦!!!
https://www.luogu.org/problemnew/solution/P2822

——————————————————————————————
然後,下面是我們的正文
我們是可以直接用公式暴力的,但是你可曾考慮到了資料範圍…………(博主只拿了20分)
這道題其實有很多細節,可以看出一丟丟思路(當然,一開始我也沒看出來,之後,打完程式碼之後再看了好幾遍題)
1.
在這裡插入圖片 描述
在這個範圍中,可以看出 j 的範圍是肯定要小於 i 的,(這裡先不要考慮m的範圍

,m的範圍在之後會有用),那麼,我們在舉幾個例子,
當i=0時,j=0;
當i=1時,j=0,1;
當i=2時,j=0,1,2;
……
這時候,我們可以看出這貌似是個三角形(我覺得思維遷徙能力比較強的,就應該已經想到了楊輝三角(因為組合數是和楊輝三角有關係的))
思維遷徙能力不好的,不要怕,因為博主就是……
那麼思考一下,為什麼上面博主說和楊輝三角有關係呢,這個時候就應該想到打表了吧,不知道為什麼有關係,幾個資料證實一下就可以了(用公式啊)自己實現
之後,我們就可以發現數據是這樣的1 11 121 1331 14641 …,這不就是楊輝三角!!!當發現這個的時候,有思路了吧,暴力啊,可是你在看一眼資料範圍……,(博主的暴力只拿了55分……)
之後再考慮其他的方法,在這裡引入一個新的概念“字首和

不懂的找度娘,這裡只說一個公式,s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1];
上加左減左上
然後看一下程式碼

	#include<bits/stdc++.h>
	using namespace std;
	int c[2100][2100];
	int s[2100][2100];//求字首和的陣列
	int t,k;
	int n,m;
	void zhs()
	{
	    c[0][0]=c[1][0]=c[1][1]=1;
	    for(int j=2;j<=2010;j++)
	    {
	        c[j][0]=1;
	        for(int l=1;l<=j;l++)
	        {
	            s[j][l]=s[j-1][l]+s[j][l-1]-s[j-1][l-1];//就是上面的公式
	            c[j][l]=(c[j-1][l-1]%k+c[j-1][l]%k)%k;
	            if(c[j][l]%k==0)	s[j][l]+=1;
	        }	
	        s[j][j+1]=s[j][j];//敲黑板,劃重點,這個必須有!!詳見下面的解釋
	    }			
	}
	int main()
	{
	    //freopen("1.in","r",stdin);
	    scanf("%d%d",&t,&k);
	    zhs();
	    for(int i=1;i<=t;i++)
	    {
	        scanf("%d%d",&n,&m);
	        if(m>n)	cout<<s[n][n]<<endl;
	        else 	cout<<s[n][m]<<endl;
	    }
	    return 0;
	}

注:s[j][j+1]=s[j][j];
假使沒有這一句,我們看一下輸出(根據第二個樣例)
0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 1 0 2 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 1 0 3 0 3 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 1 0 4 0 6 0 4 0 1 0 0 0 0 0 0 0 0 0 0 0 0
0 1 1 5 2 10 3 10 4 5 *4 1 ** 0 0 0 0 0 0 0 0 0 0
0 1 1 6 3 15 5 20 7 15 7 6 3 1 0 0 0 0 0 0 0 0
0 1 1 7 3 21 6 35 9 35 9 21 **5 7 * 2 1 0 0 0 0 0 0
0 1 1 8 3 28 6 56 10 70 10 56 6 28 ***3 8 *** 1 1 0 0 0 0
0 1 1 9 3 36 6 84 10 126 10 126 6 84 3 36 1 9 0 1 0 0
0 1 2 10 5 45 9 120 14 210 14 252 11 210 9 120 8 45 8 10 8 1
只有黑體的地方就是s[j][j+1]的地方,但是,我們可以明顯的發現到不對,這個資料不對……怎麼辦??
這就是上面的解決的妙處了,傳遞,將 有下劃線的數字傳遞給黑體數字,這樣!!!!不就解決了,對吧