• 【BZOJ1801】中国象棋


    题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1801


    很久之前就听说过这道题了,当时就觉得很难。。。

    一种很暴力的思想是,用状压DP做,记录每一行的各个状态,但显然,只可以拿50分(也不少)。

    这里用到一种DP优化的思想,合并本质相同的状态,实际上,我们并不太关心每一行的摆放情况,真正影响方案数的是,放到某一行,已经放了1个的列数,放了2个的列数及空列,知道了这些就可以进行转移了。

    所以设dp[i][j][k]表示放到第i行,放了1个的列有j个,放了2个的列有k个,自然空列就是m-j-k。

    然后分类讨论第i行的摆放情况,可以一个也没放,可以放一个在空列或放了1个的列,可以放两个在空列,一个在空列一个在放了一个的列,两个都在放了一个的列。

    然后对于dp[n][j][k]进行累加统计答案即可。

     1 #include <cstdio>
     2 
     3 typedef long long ll;
     4 
     5 const int maxn = 105, maxm = 105, p = 9999973;
     6 
     7 ll dp[maxn][maxm][maxm];
     8 
     9 inline int c(int x) {
    10     return x * (x - 1) / 2;
    11 }
    12 
    13 int main() {
    14     int n, m;
    15     ll ans = 0;
    16     scanf("%d%d", &n, &m);
    17     dp[0][0][0] = 1;
    18     for (int i = 1; i <= n; ++i)
    19         for (int j = 0; j <= m; ++j)
    20             for (int k = 0; k <= m - j; ++k) {
    21                 dp[i][j][k] = dp[i - 1][j][k];
    22                 if (j >= 1) dp[i][j][k] += dp[i - 1][j - 1][k] * (m - j - k + 1);
    23                 if (k >= 1) dp[i][j][k] += dp[i - 1][j + 1][k - 1] * (j + 1);
    24                 if (j >= 2) dp[i][j][k] += dp[i - 1][j - 2][k] * c(m - j - k + 2);
    25                 if (k >= 1) dp[i][j][k] += dp[i - 1][j][k - 1] * (m - j - k + 1) * j;
    26                 if (k >= 2) dp[i][j][k] += dp[i - 1][j + 2][k - 2] * c(j + 2);
    27                 dp[i][j][k] %= p;
    28                 if (i == n) ans = (ans + dp[i][j][k]) % p;
    29             }
    30     printf("%lld", ans);
    31     return 0;
    32 }
    AC代码
  • 相关阅读:
    【Docker】 CentOS7 安装 Docker 及其使用方法 ( 一 )
    js加密解密
    JSON.parse和eval()的区别
    复选框(全选/全不选/反选)
    圆形进度条
    C# JToken类,实现解析动态json数据、遍历、查找
    使IIS服务器支持下载 apk/ipa 安装包
    Python关键字
    C#泛型(二)泛型类
    C#泛型(一)泛型方法
  • 原文地址:https://www.cnblogs.com/Mr94Kevin/p/9890907.html
Copyright © 2020-2023  润新知