[NOIP模擬賽]排列問題

題目描述
長度爲N的排列是一個序列(a1, a2, ..., an),恰好包含從1到N的每一個數字。例如,(3, 1, 4, 5, 2)是一個長度爲5的排列。
對於兩個排列a和b,定義magic(a, b) = max(a1, b1) + max(a2, b2) + ... + max(an, bn)

給定整數N和K,求有多少對排列a和b 滿足a和b的長度都爲N,並且magic(a, b) ≥ K。


輸入格式

第1行:2個整數N(N≤50)和K(K≤2500)


輸出格式

第1行:1個整數,表示答案,答案模1,000,000,007


輸入樣例

2 4


輸出格式

2


樣例說明
2個長度爲2的排列一共有4種情況:
magic( (1,2), (1,2) ) = 1+2 = 3
magic( (1,2), (2,1) ) = 2+2 = 4
magic( (2,1), (1,2) ) = 2+2 = 4
magic( (2,1), (2,1) ) = 2+1 = 3
magic值大於等於4的有2對排列。



題解

設a排列:|   |   |   |   |   |,

設b排列:|   |   |   |   |   |,上下對應爲一組格子

設dp[ful][haf][s]表示格子中有ful組全滿, 2*haf組半滿, 值爲s時的總方案數


以n=5爲例,

假設已有下面的狀態:

|   | 5 | 4 |   |   |

|   |   | 5 | 4 |   |,現在要將數字3填進去,一共有4種轉移方式:


①佔2組半空格子:

|   | 5 | 4 | 3 |   |

|   | 3 | 5 | 4 |   |

a列有haf個空位可供選擇,b列有haf個空位可供選擇,對方案數的貢獻爲haf*haf,由於數是從大到小枚舉,s值不變;


②佔1組半空格子,1組全空格子:

|   | 5 | 4 | 3 |   |

| 3 |   | 5 | 4 |   |

a列有haf個空位可供選擇,b列有emp個空位可供選擇,當然也可以a列選emp個,b列選haf個,對方案數的貢獻爲haf*emp*2,因爲填了一個全空格子,s值增大3;


③佔2組全空格子,不錯開

| 3 | 5 | 4 |   |   |

| 3 |   | 5 | 4 |   |

a列有emp個空位可供選擇,b列有emp個空位可供選擇,對方案數的貢獻爲emp*emp,因爲填了1個全空格子,s值增大3;


④佔2組全空格子,錯開

| 3 | 5 | 4 |   |   |

|   |   | 5 | 4 | 3 |

a列有emp個空位可供選擇,因爲要錯開,b列有emp-1個空位可供選擇,對方案數的貢獻爲emp*(emp-1),因爲填了2個全空格子,s值增大3*2;


#include<cstdio>
const int Mod=1e9+7;
const int N=55;
int n, maxs, k, dp[N][N][N*N], sum;

int main() {
	scanf( "%d%d", &n, &k ); maxs=n*n;
	dp[0][0][0]=1;
	for( int num=n; num>=1; num-- ) {//從大到小枚舉
		int cnt=n-num;//已經填了cnt個數
		for( int ful=0; ful<=cnt; ful++ ) {//ful組格子全滿
			int haf=cnt-ful, emp=n-ful-haf*2;//2*half組格子半滿, emp組格子全空
			for( int s=0; s<=maxs; s++ ) {
				if( !dp[ful][haf][s] ) continue;
				if( haf )//佔2組半空格子
					( dp[ful+2][haf-1][s]+=1ll*dp[ful][haf][s]*haf*haf%Mod )%=Mod;
				if( emp ) {
					//佔1組半空格子, 1組全空格子
					( dp[ful+1][haf][s+num]+=1ll*dp[ful][haf][s]*emp*haf*2%Mod )%=Mod;
					//佔2組全空格子(不錯開)
					( dp[ful+1][haf][s+num]+=1ll*dp[ful][haf][s]*emp%Mod )%=Mod;
					if( emp>=2 )//佔2組全空格子(錯開)
						( dp[ful][haf+1][s+2*num]+=1ll*dp[ful][haf][s]*emp*(emp-1)%Mod )%=Mod;
				}
			}
		}
	}
	for( int i=k; i<=maxs; i++ ) sum=( sum+dp[n][0][i] )%Mod;
	printf( "%d\n", sum );
	return 0;
}

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