這個題,是一個DP,令人驚訝,我當時根本就沒往這方面想,還是題見得少了
同學有一個DP解法,個人感覺比標解好理解得多,具體如下:
如圖:
將數字1 ~ N從大到小填
定義Dp[full][half][sum]表示
已經填了full個格子(上下對應都填了, 如:上4下5)
有2 * half個格子填了一半(如:紅色點的兩個格子,由於這種格子必然是偶數個,所以除2)
已經填的數的總和是sum
Dp值是此時的方案數。
這題的轉移有三種情況,
以上圖爲例,現在應該填now = 3:
1,分別填在兩個藍色格子內,並使他們無法組成一個新的full,此時有N - full - (half - 1) * 2個上下同時爲空的格子,所以:
Dp[full][half][sum] += Dp[full][half - 1][sum - 2 * now] * (N - full - (half - 1) * 2) * (N - full - (half - 1) * 2 - 1) % MOD;
2,使成爲一個新的full(直接填在一對對應的空格子裏(藍色), 或者填一個在紅色格子裏,再填一個在藍色格子裏,half值不變,將損失1對full):
Dp[full][half][sum] += Dp[full - 1][half][sum - now] * (half * 2 * (N - half *2 - (full - 1)) + N - half * 2 - (full - 1));
3,使成爲一個新的full(填在兩個半格里(紅色),將損失1對half):
Dp[full][half][sum] += Dp[full - 2][half + 1][sum] * (half + 1) * (half + 1);
最後的答案是 Σ Dp[N][0][sum](sum >= K)
下面是標解,和上面的解法有所不同:
Code:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
using namespace std;
const int MOD = 1e9 + 7;
int N, K, L, Ans;
int Dp[55][55][55 * 55];
bool getint(int & num){
char c; int flg = 1; num = 0;
while((c = getchar()) < '0' || c > '9'){
if(c == '-') flg = -1;
if(c == -1) return 0;
}
while(c >= '0' && c <= '9'){
num = num * 10 + c - 48;
if((c = getchar()) == -1) return 0;
}
num *= flg;
return 1;
}
int P(int x){
int rt = 1;
for(int i = 2; i <= x; ++ i)
rt = 1ll * rt * i % MOD;
return rt;
}
int main(){
freopen("data1.in", "r", stdin);
//freopen("permutation.in", "r", stdin);
//freopen("permutation.out", "w", stdout);
getint(N), getint(K);
int up = N * N;
Dp[0][0][0] = 1;
for(int i = 1; i <= N; ++ i){
int now = N - i + 1;
for(int full = 0; full <= i; ++ full){
int half = i - full;
for(int s = 0; s <= up; ++ s){
if(s >= now * 2 && N - full - (half - 1) * 2 > 0)
Dp[full][half][s] = (Dp[full][half][s] + 1ll*Dp[full][half-1][s-(now << 1)]*(N-full-((half-1)<<1))%MOD*(N-full-((half-1)<<1)-1)%MOD)%MOD;
if(full && s >= now)
Dp[full][half][s] = (Dp[full][half][s] + 1ll*Dp[full-1][half][s-now]*((half*(N-(half<<1)-(full-1))<<1)%MOD+N-(half<<1)-(full-1))%MOD)%MOD;
if(full >= 2)
Dp[full][half][s] = (Dp[full][half][s] + 1ll*Dp[full-2][half+1][s]*(half+1)%MOD*(half+1)%MOD)%MOD;
}
}
}
int Ans = 0;
for(int i = K; i <= up; ++ i)
Ans = (Ans + Dp[N][0][i]) % MOD;
printf("%d\n", Ans);
return 0;
}