【題解】中國象棋

題目大意

  在一個\(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;
}
相關文章
相關標籤/搜索