[AHOI2009] 中国象棋

[AHOI2009] 中国象棋

题目大意:在一个(N)(M)列的棋盘上,让你放若干个炮,求让这些炮不互相攻击的摆放方法有多少种

经过思考,我们可以发现,你按照行来枚举,和之前行的关系所在,只有不能放在那些摆放了两个炮的列上.

这样来DP

  • 状态:设(f[i][j][k])为到(i)行为止,有(j)列放了一个棋子,有(k)列放了两个棋子,共有多少种可能的方案.

  • 状态转移:代码中有注释的那几行就是

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

const int Mod = 9999973;

int n, m;
long long f[105][105][105], ans;

inline int C(int num){
    return num * (num - 1) / 2;
}

int main(){
    scanf("%d %d", &n, &m);
    f[0][0][0] = 1;
    for(int i = 1; i <= n ;++i)
        for(int j = 0; j <= m; ++j)
            for(int k = 0; k + j <= m; ++k){
                f[i][j][k] = (f[i][j][k] + f[i - 1][j][k]) % Mod;//不放
                if(j && m - j - k + 1 >= 1)
                    f[i][j][k] = (f[i][j][k] + (f[i - 1][j - 1][k] * (m - j - k + 1)) % Mod ) % Mod;//放一个在空着的列
                if(k)
                    f[i][j][k] = (f[i][j][k] + (f[i - 1][j + 1][k - 1] * (j + 1)) % Mod ) % Mod;//放一个在j列上
                if(j > 1 && m - j - k + 2 >= 2)
                    f[i][j][k] = (f[i][j][k] + (f[i - 1][j - 2][k] * C(m - j - k + 2)) % Mod ) % Mod;//放两个在空列上
                if(k >= 2)
                    f[i][j][k] = (f[i][j][k] + (f[i - 1][j + 2][k - 2] * C(j + 2)) % Mod ) % Mod;//放在两个j列上
                    
                if(k >= 1 && j && m - k + 1 - j >= 1)
                    f[i][j][k] = (f[i][j][k] + (f[i - 1][j][k - 1] * ((m - k + 1 - j) * j) % Mod ) % Mod ) % Mod;//一个放在j列上,一个放在空列上

            }
    for(int i = 0; i <= m; ++i)
        for(int j = 0; j + i <= m; ++j){
            ans = (ans + f[n][i][j]) % Mod;
        } 
            
    printf("%d
", ans);
    return 0;
}

错误qwq

  • (long long),不然乘的时候会炸掉
  • 一个放在(j)列上,一个放在空列上的情况,是乘上(m-k+1-j)(j)
原文地址:https://www.cnblogs.com/LMSH7/p/9531866.html