# BZOJ4806_炮

解:


本质上就是说,每行或每列上不能放大于等于三个炮

考虑这样一个dp:

令f[i][j][k]表示:前i行,有j列没放,有k列放一个,((m - j - k)列放了两个)

则有如下转移:

1、这一行不放,\(f[i][j][k] = f[i - 1][j][k]\)

2、这一行放一个:

2.1、这一个放在一个没放的列上:\(f[i][j][k] += f[i - 1][j + 1][k - 1] * C_{j + 1}^{1}\)

2.2、这一个放在一个有一个的列上:\(f[i][j][k] += f[i - 1][j][k + 1] * C_{k + 1}^{1}\)

3、这一行放两个:

3.1、两个都放在没放的列上: \(f[i][j][k] += f[i - 1][j + 2][k - 2] * C_{j + 2}^{2}\)

3.2、两个一个放在没放的列上,一个放在一个的列上: \(f[i][j][k] += f[i - 1][j + 1][k] * C_{j + 1}^{1} * C_{k}^{1}\)

3.3、两个都放在一个的列上: \(f[i][j][k] += f[i - 1][j][k + 2] * C_{k + 2}^{2}\)


按照如上方程逐个转移即可

特别的,初始化:

先算出第一行的答案,

\(f[1][m][0] = 1\)

\(f[1][m - 1][1] = C_{m}^{1} = m\)

\(f[1][m - 2][2] = C_{m}^{2}\)

然后i从第二行开始枚举

代码:


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int md = 999983;
ll n, m, ans;
ll f[110][110][110];

ll C(ll x, ll y) {
    if (y == 1) return x;
    return ((x * (x - 1)) / 2) % md;
}//因为y只有1和2两种取值,所以就简写了
//1079364439
int main() {
    scanf("%lld%lld", &n, &m);
    f[1][m][0] = 1;
    f[1][m - 1][1] = m;
    f[1][m - 2][2] = C(m, 2);
    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]) % md;

                if (k >= 1 && j + 1 <= m) f[i][j][k] = 
                    (f[i][j][k] + f[i - 1][j + 1][k - 1] * C(j + 1, 1)) % md;
                if (k + 1 <= m) f[i][j][k] = 
                    (f[i][j][k] + f[i - 1][j][k + 1] * C(k + 1, 1)) % md;

                if (k >= 2 && j + 2 <= m) f[i][j][k] = 
                    (f[i][j][k] + f[i - 1][j + 2][k - 2] * C(j + 2, 2)) % md;
                if (j + 1 <= m) f[i][j][k] = 
                    (f[i][j][k] + f[i - 1][j + 1][k] * C(j + 1, 1) * C(k, 1)) % md;
                if (k + 2 <= m) f[i][j][k] = 
                    (f[i][j][k] + f[i - 1][j][k + 2] * C(k + 2, 2)) % md;
            }
        }
    }
    for (int j = 0; j <= m; j++)
        for (int k = 0; k <= m; k++)
            ans = (ans + f[n][j][k]) % md;
    cout << ans << endl;
    return 0;
}

一定看清模数到底是多少,不要像我一样查半天最后发现是模数打错了

posted @ 2020-08-19 07:40  熹圜  阅读(115)  评论(0)    收藏  举报