題目描述
長度爲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; }
[NOIP模擬賽]排列問題
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.