题目描述见链接 .
- 可以发现每行每列最多只能够放 个棋子 .
设 表示前 行,前 列,第 行放置了 个棋子, 第 列放置 个棋子的方案数, 发现不可行.
- 发现可以不用关心棋子的顺序 .
设 表示前 行, 有 列放了 个棋子, 列放了 个的方案数,
为什么这样设状态? 因为这样设状态可以方便的得知放 个棋子的列数是 .
考虑按行转移:
-
第 行放 个棋子,
. -
第 行放 个棋子,
. -
不放棋子, (这个容易忘记) .
.
到这里, 相信已经有人发现了不对的地方, 上面标红色井号的方程是不是显得有些太简单了 …
原来是状态的转移没考虑到全部情况, 即有多种方式从 行的状态到 行状态,
下面重新写一遍状态转移方程,
-
第 行放 个棋子,
. -
第 行放 个棋子,
. -
不放棋子, (这个容易忘记) .
.
最后答案即为 .
- 初值 .
- 由于要用到的组合数 都等于 , 于是直接计算即可 .
#include<bits/stdc++.h>
const int mod = 9999973;
const int maxn = 105;
typedef long long LL;
int N, M;
int dp[maxn][maxn][maxn];
int C(int m){ return m*(m-1) >> 1; }
int main(){
scanf("%d%d", &N, &M);
dp[0][0][0] = 1;
for(int i = 1; i <= N; i ++)
for(int j = 0; j <= M; j ++)
for(int k = 0; k <= M; k ++){
dp[i][j][k] = dp[i-1][j][k];
if(k-1 >= 0) dp[i][j][k] = ((LL)dp[i][j][k] + dp[i-1][j+1][k-1] * (j+1)) % mod;
if(j-1 >= 0 && (M-(j-1)-k)) dp[i][j][k] = ((LL)dp[i][j][k] + (LL)dp[i-1][j-1][k] * (M-(j-1)-k) % mod) % mod;
if(j-2 >= 0 && (M-(j-2)-k)) dp[i][j][k] = ((LL)dp[i][j][k] + (LL)dp[i-1][j-2][k] * C(M-(j-2)-k) % mod) % mod;
if(k-1 >= 0 && (M-j-(k-1))) dp[i][j][k] = ((LL)dp[i][j][k] + (LL)(dp[i-1][j][k-1] * (M-j-(k-1)) % mod)* j % mod) % mod;
if(k-2 >= 0) dp[i][j][k] = ((LL)dp[i][j][k] + (LL)dp[i-1][j+2][k-2] * C(j+2) % mod) % mod;
}
int Ans = 0;
for(int j = 0; j <= M; j ++)
for(int k = 0; k <= M; k ++)
Ans = ((LL)Ans + dp[N][j][k]) % mod;
printf("%d", Ans);
return 0;
}