[AHOI2009] 中国象棋

[AHOI2009] 中国象棋

蛮简单的一道 DP .

显然, 每行每列都最多只有 2 个炮, 所以我们设 f[i][j][k] 表示第 i 行, j 列有 1 个炮, k 列有 2 个炮的方案数.

然后转移就很简单了, 只需要枚举当前行放的一个或者两个炮放到哪里就行了.

像这种合法不合法只与单行或单列的数量有关的, 我们设状态就可以只存数量为多少的行或列的数量就可以了, 转移的时候用组合来计算我们共有多少种转移方案.

code:

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef unsigned long long ull;

int read() {
  int x = 0, f = 1;
  char ch = getchar();
  for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = -1;
  for (; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + (ch ^ 48);
  return x * f;
}

const int N = 105, mod = 9999973;

int n, m;
ll ans, f[N][N][N];

int main() {
  n = read(), m = read();
  f[0][0][0] = 1;
  for (int i = 1; i <= n; i++) {
    for (int j = m; j >= 0; j--) {
      for (int k = m - j; k >= 0; k--) {
        f[i][j][k] += f[i - 1][j][k];
        if (m - j - k) f[i][j + 1][k] = (f[i][j + 1][k] + f[i - 1][j][k] * (m - j - k)) % mod;
        if (m - j - k > 1) f[i][j + 2][k] = (f[i][j + 2][k] + (f[i - 1][j][k] * (m - j - k) * (m - j - k - 1) >> 1)) % mod;
        if (j) f[i][j - 1][k + 1] = (f[i][j - 1][k + 1] + f[i - 1][j][k] * j) % mod;
        if (j > 1) f[i][j - 2][k + 2] = (f[i][j - 2][k + 2] + (f[i - 1][j][k] * j * (j - 1) >> 1)) % mod;
        if (m - j - k && j) f[i][j][k + 1] = (f[i][j][k + 1] + f[i - 1][j][k] * j * (m - j - k)) % mod;
      }
    }
  }
  for (int i = 0; i <= m; i++) {
    for (int j = 0; j <= m - i; j++) {
      ans += f[n][i][j];
    }
  }
  printf("%lld", ans % mod);
  return 0;
}
posted @ 2021-09-26 15:58  sshadows  阅读(33)  评论(0)    收藏  举报
编辑推荐:
· 一则复杂 SQL 改写后有感
· golang中写个字符串遍历谁不会?且看我如何提升 50 倍
· C# 代码如何影响 CPU 缓存速度?
· 智能桌面机器人:使用 .NET 为树莓派开发 Wifi 配网功能
· C# 模式匹配全解:原理、用法与易错点
阅读排行:
· 一则复杂 SQL 改写后有感
· 曾经风光无限的 Oracle DBA 已经落伍了吗?
· 接口被刷百万QPS,怎么防?
· C# 锁机制全景与高效实践:从 Monitor 到 .NET 9 全新 Lock
· 一个开源免费、功能丰富的 WPF 自定义控件资源库
点击右上角即可分享
微信分享提示