[AHOI2009]中国象棋

Posted hs-black

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[AHOI2009]中国象棋相关的知识,希望对你有一定的参考价值。

[AHOI2009]中国象棋

题意:

在一个N行M列的棋盘上,让你放若干个炮(可以是0个),使得没有一个炮可以攻击到另一个炮,请问有多少种放置方法。

这题很久以前就见过了, 但当时dp太菜, 一看计数就不敢做了. 现在一看, 不是水题吗

显然的思路应该是记录一下每行放了几个炮, 但行太多肯定记录不下, 由炮的性质可知一行最多2个炮, 于是我们有了正确的解法

(f[i][j][k])表示前(i)列有(j)行没放炮, (k)列放了1个炮的方案数, 然后枚举当前列放几个炮, 注意放两个的时候要用组合数转移

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define ll long long
using namespace std;
const int P = 9999973;

template <typename T>
void read(T &x) {
    x = 0; bool f = 0;
    char c = getchar();
    for (;!isdigit(c);c=getchar()) if (c=='-') f=1;
    for (;isdigit(c);c=getchar()) x=x*10+(c^48);
    if (f) x=-x;
}

template <typename T>
void write(T x) {
    if (x < 0) putchar('-'), x = -x;
    if (x >= 10) write(x / 10);
    putchar('0' + x % 10);
}

int n, m;
const int N = 200;
ll f[N][N][N]; // 0 1  

inline void add(ll &x, ll y) {
    (x += y) %= P;
}

ll ans = 0;
int main() {
    read(n), read(m);
    f[0][n][0] = 1;
    for (int i = 1;i <= m; i++) {
        for (int j = 0;j <= n; j++) {
            for (int k = 0;k + j <= n; k++) {
                ll x = 0;
                add(x, f[i-1][j][k]);
                if (k) add(x, (j + 1) * f[i-1][j+1][k-1]);
                add(x, (k + 1) * f[i-1][j][k+1]);
                add(x, (ll)(j + 1) * k % P * f[i-1][j+1][k]);
                if (k >= 2) add(x, (ll)(j + 2) * (j + 1) / 2 % P * f[i-1][j+2][k-2]);
                add(x, (ll)(k + 2) * (k + 1) / 2 % P * f[i-1][j][k+2]);
                f[i][j][k] = x;
            }
        }
    }
    for (int i = 0;i <= n; i++) 
        for (int j = 0;j + i <= n; j++) 
            (ans += f[m][i][j]) %= P;
    cout << ans << endl;
    return 0;
}

以上是关于[AHOI2009]中国象棋的主要内容,如果未能解决你的问题,请参考以下文章

JZOJ 1667 ( bzoj 1801 ) [ AHOI 2009 ] 中国象棋 —— DP

[AHOI2009]中国象棋 题解

bzoj1801 [Ahoi2009]chess 中国象棋

[AHOI2009]中国象棋

P2051 [AHOI2009]中国象棋

BZOJ1801: [Ahoi2009]chess 中国象棋