洛谷 P2051 [AHOI2009]中国象棋

题意简述

在N行M列的期盘中,放若干个炮,使它们两两不能打到,求总共的方案数

题解思路

DP,dp[i][j][k]表示前i行有j列放置1个炮,有k列放置2个炮
分6种情况转移
1.不放炮,直接到下一行
2.在没放炮的那一列放1个炮,j+1
3.在没放炮的两列分别放1个炮,j+2
4.在放一个炮的那一列放1个炮,j-1,k+1
5.在放一个炮的两列分别放1个炮,j-2,k+2
6.同时在没放炮的一列和放一个炮的一列分别放一个炮,k+1

代码

#include <cstdio>
using namespace std;
typedef long long ll;
const int mod = 9999973;
int n, m, ans;
int dp[200][200][200];
void add(int &x, int y) {x = ((ll)x + y) % mod; }
int C(int x) {return (ll)x * (x - 1) / 2 % mod; }
int main()
{
    scanf("%d%d", &n, &m);
    dp[0][0][0] = 1;
    for (register int i = 0; i <= n; ++i)
        for (register int j = 0; j <= m; ++j)
            for (register int k = 0; k <= m - j; ++k)
            {
                add(dp[i + 1][j][k], dp[i][j][k]);
                if (m - j - k) add(dp[i + 1][j + 1][k], (ll)dp[i][j][k] * (m - j - k) % mod);
                if (m - j - k >= 2) add(dp[i + 1][j + 2][k], (ll)dp[i][j][k] * C(m - j - k) % mod);
                if (j) add(dp[i + 1][j - 1][k + 1], (ll)dp[i][j][k] * j % mod);
                if (j >= 2) add(dp[i + 1][j - 2][k + 2], (ll)dp[i][j][k] * C(j) % mod);
                if (m - j - k && j) add(dp[i + 1][j][k + 1], (ll)dp[i][j][k] * (m - j - k) * j % mod);
            }
    for (register int i = 0; i <= m; ++i) 
        for (register int j = 0; j <= m - i; ++j)
            add(ans, dp[n][i][j]);
    printf("%d\n", ans);
}

猜你喜欢

转载自www.cnblogs.com/xuyixuan/p/9594103.html
今日推荐