2019.11.29 T2【動態規劃】 不等數列(num)

T2

【題目描述】

11nn任意排列,然後在排列的每兩個數之間根據他們的大小關係插入>“>”<“<”。問在所有排列中,有多少個排列恰好有kk<“<”。答案對20122012取模。

【輸入格式】

第一行22個整數n,kn,k

【輸出格式】

一個整數表示答案。

【樣例輸入】

5 2

【樣例輸出】

66

【數據範圍】

對於3030%的數據:n<=10n <= 10
對於100100%的數據:k<n<=1000k < n <= 1000


思路:
看到這一題,求方案數,那肯定就是動態規劃啦。

假設我們已經把前 i1i - 1 個數排列好並且已經標號 >> 號以及 << 號,這時候我們在增加i這個數,有 i+1i + 1 個位置可以選擇。但有一點需要注意的是,不論插在哪兩個數中間(即不論替換掉哪個不等號),形式都爲<i>“< i >”(或i>“i >”<i“< i”)。

舉個例子,若已有不等數列:1<3>2<41 < 3 > 2 < 4

接下來我們插入 55 這個數,則有 55 種情況:

5>1<3>2<4①5 > 1 < 3 > 2 < 4
1<5>3>2<4②1 < 5 > 3 > 2 < 4
1<3<5>2<4③1 < 3 < 5 > 2 < 4
1<3>2<5>4④1 < 3 > 2 < 5 > 4
1<3>2<4<5⑤1 < 3 > 2 < 4 < 5

然後我想到的就是表示狀態的方法:用f[i][j]f[i][j]表示用11 ~ ii組成的不等數列中,<“<”號數等於jj的方案數。

接下來思考的就是狀態轉移方程。

首先,我們可以推出f[i][j]f[i][j]f[i+1][j+1]f[i+1][j+1]的關係,即增加一個小於號有多少種方案。

不難推出,f[i+1][j+1]+=(ij)f[i+1][j+1]+=(i-j)(原本不等數列大於號的數量加上11,即原本符號數i1i-1減去原本小於號數 jj11(若i+1i+1在數列最前面),即用<i+1>“< i+1 >”,代替>“>”,相當於增加一個<“<”f[i][j]*f[i][j]

然後推出f[i][j]f[i][j]f[i+1][j]f[i+1][j]的關係,即增加一個大於號有多少種方案。

f[i+1][j]+=(j+1)f[i+1][j]+=(j+1)(原本不等數列小於號的數量加上1)f[i][j]*f[i][j]

最後是邊界:f[2][0]=1(2>1),f[2][1]=1(1<2)f[2][0]=1(2>1),f[2][1]=1(1<2)


以上就是我自己的思路,附上100100分代碼:

#include<bits/stdc++.h>
#define N 1000+10
using namespace std;

int mod=2012;
int f[N][N];
int n,k;

int main(){
	memset(f,0,sizeof(f));
	cin>>n>>k;
	f[2][0]=1;f[2][1]=1;
	
	for(int i=2;i<=n;i++)
		for(int j=0;j<i;j++){
			f[i+1][j+1]=(f[i+1][j+1]+(i-j)*f[i][j])%mod;
			f[i+1][j]=(f[i+1][j]+(j+1)*f[i][j])%mod;
		}
		
	cout<<f[n][k];
	return 0;
}

注意模數!


接下來附上老師提供的題解:

對於3030% n<=10n<=10的數據,搜索打表,狀態壓縮動態規劃…

對於1n1--n等類似的排列計數問題,以動態規劃和組合數學22種大方向爲基本解決方向。

組合數學在noipnoip最難也就到楊輝三角左右,所以這題我從動態規劃展開。

如果此類排列問題在腦中的模型是:“有nn個格子,填入1n1--n”,那麼相對應的DPDP就不得不記錄哪些數填過了(從左到右填入)或者哪些格子填過了(從小到大填入)。這樣一來就必須要使用狀態壓縮來存儲這些信息,就使得複雜度變得難以接受。

而如果換個模型:“從小到大把數字插入數列”。注意是數列而不是格子,這樣一來就不需要記錄是哪些數字插入了(而只要記錄插入到了第幾個數字),同時不需要記錄每個數字的具體位置,也不需要記錄數字的相對位置,而只需記錄相對關係的數目(對本題而言就是有幾個<“<”)。

因爲是從小到大插入數字,所以當前插入的數字一定大於所有已經插入的。
在這裏插入圖片描述
藍色是當前插入的數字,如果它插入到<<關係的22個數字之間(或者數列最左端),就會使數列的<<數量不變,>>數量+1+1
在這裏插入圖片描述
類似的,插入到>>關係的22個數字之間(或者數列最右端),數列的<<數量+1+1>>數量不變。

F[i][j]F[i][j]表示前ii個數字構成的數列中,恰有jj<‘<’號的方案數(>‘>’號就有ij1i-j-1個)。

F[i][j]=F[i1][j1](ij)+F[i1][j](j+1)F[i][j]=F[i-1][j-1]*(i-j)+F[i-1][j]*(j+1).

時空複雜度:O(n2)O(n^2)

若打表則時間複雜度爲O(1)O(1)


完結撒花!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章