在一個\(n\)行\(m\)列的棋盤上(\(1 \leq n,m \leq 100\)),要求每行每列最多能放\(2\)個棋子,求方案數$\bmod 9999973
$。ios
比較有意思的dp。
咱們能夠設\(dp[I][i][j][k]\)表示從第\(1\)到第\(I\)行,有\(i\)列只有\(1\)個棋子,有\(j\)列只有\(2\)個棋子,有\(k\)列只有\(0\)個棋子的總方案數。
顯然\(k\)能夠由\(m\)和\(i\)、\(j\)獲得,能夠去掉這一維。固然也能夠用滾動數組優化。
由於每行每列都最多能放\(2\)個棋子因此dp的狀態轉移方程只有最多\(5\)種狀況,分別枚舉便可,具體看下面的代碼應該都能理解。數組
#include <iostream> #define MAX_N 100 #define MAX_M 100 #define MOD 9999973 using namespace std; int n, m; long long dp[MAX_N | 1][MAX_N | 1][2]; // i:有1個棋子的列 // j:有2個棋子的列 int ans; inline int C(int x) { return x * (x + 1) >> 1; } int main() { cin >> n >> m; dp[0][0][1] = 1; dp[1][0][1] = m; dp[2][0][1] = C(m - 1); for(register int k = 2; k <= n; ++k) { for(register int i = 0; i <= m; ++i) { for(register int j = 0; i + j <= m; ++j) { dp[i][j][k & 1] = dp[i][j][k + 1 & 1]; if(i) dp[i][j][k & 1] = (dp[i][j][k & 1] + dp[i - 1][j][k + 1 & 1] * (m - i - j + 1)) % MOD; if(i > 1) dp[i][j][k & 1] = (dp[i][j][k & 1] + dp[i - 2][j][k + 1 & 1] * C(m - i - j + 1)) % MOD; if(j) dp[i][j][k & 1] = (dp[i][j][k & 1] + dp[i + 1][j - 1][k + 1 & 1] * (i + 1)) % MOD; if(j > 1) dp[i][j][k & 1] = (dp[i][j][k & 1] + dp[i + 2][j - 2][k + 1 & 1] * C(i + 1)) % MOD; if(i && j) dp[i][j][k & 1] = (dp[i][j][k & 1] + dp[i][j - 1][k + 1 & 1] * i * (m - i - j + 1)) % MOD; } } } for(register int i = 0; i <= m; ++i) { for(register int j = 0; i + j <= m; ++j) { ans += dp[i][j][n & 1]; // cout << m - i - j << " " << i << " " << j << ": " << dp[i][j][n & 1] << endl; // debug if(ans >= MOD) ans -= MOD; } } cout << ans; return 0; }