这次小可可想解决的难题和中国象棋有关,在一个N行M列的棋盘上,让你放若干个炮(可以是0个),使得没有一个炮可以攻击到另一个炮,请问有多少种放置方法。大家肯定很清楚,在中国象棋中炮的行走方式是:一个炮攻击到另一个炮,当且仅当它们在同一行或同一列中,且它们之间恰好 有一个棋子。你也来和小可可一起锻炼一下思维吧!

题目链接🔗

[AHOI2009]中国象棋

题解

不像状压DP的多维DP
因为每行每列都最多只能摆两个炮
DP[i][j][k] 表示前i行,其中j列有1个炮,k列有两个炮的摆法方案数
然后一列列往下,每次位置加1或者2个炮,由当前位置推后面位置炮的个数

代码

#include <cstdio>
#include <algorithm>
using namespace std;
const int mod = 9999973;
const int maxd = 105;
int n,m;
long long dp[maxd][maxd][maxd],ans;
int C(int n)
{
    return n*(n-1)/2;
}
int main()
{	
    // freopen("a.in","r",stdin);
    // freopen("k.out","w",stdout);
    scanf("%d %d",&n,&m);
    dp[0][0][0] = 1;
    for(int i=0;i<n;i++)
        for(int j=0;j<=m;j++)
            for(int k=0;k+j<=m;k++)
                if(dp[i][j][k])
                {
                    (dp[i+1][j][k] += dp[i][j][k])%=mod;//不放
                    if(m-j-k)(dp[i+1][j+1][k] += dp[i][j][k]*(m-j-k))%=mod;
                    if(j)(dp[i+1][j-1][k+1] += dp[i][j][k]*j) %=mod;
                    if(m-j-k>=2)(dp[i+1][j+2][k] += dp[i][j][k]*C(m-j-k))%=mod;
                    if(j&&(m-j-k))(dp[i+1][j][k+1] += dp[i][j][k] * j *(m-j-k))%=mod;
                    if(j>=2)(dp[i+1][j-2][k+2] += dp[i][j][k] *C(j)) %=mod;
                }
    for( int i = 0; i <= m; ++i ) // 有1个棋子的列
    for( int j = 0; i+j <= m; ++j ) { // 2个棋子的列
        ans = ( ans + dp[n][i][j] ) % mod;
    }
    printf("%lld",ans);
    return 0;
}