题目描述

这次小可可想解决的难题和中国象棋有关,在一个N行M列的棋盘上,让你放若干个炮(可以是0个),使得没有一个炮可以攻击到另一个炮,请问有多少种放置方法。大家肯定很清楚,在中国象棋中炮的行走方式是:一个炮攻击到另一个炮,当且仅当它们在同一行或同一列中,且它们之间恰好 有一个棋子。你也来和小可可一起锻炼一下思维吧!

题目大意

在一个n*m的棋盘中,求任意行和任意列上最多有2个棋子的方案总数。

感想

真的是一道DP好题,状态,转移方程都非常的难想,我也WA了好几发。

分析

看到题目,很明显可以发现的是,因为炮必须是要隔山打虎,那么任意列和任意行都不能有两个棋子。(其实我非常想把题目改成3个,这样难度有加大了)。

因为每一行每一列<=2,所以
定义状态:
\[f[i][j][k]\]
表示前\(i\)中,有\(j\)列有\(1\)个棋子,有\(k\)列有\(2\)个棋子有多少种方案数。
决策分\(3\)种:


第一种是放\(0\)个棋子
这种状态很明显只有转移,也就是可以从上一层直接推过来,\(j\)和\(k\)都不变。
转移方程:\(f[i][j][k]+=f[i-1][j][k]\)


第二种是放一个\(1\)个棋子:

  • \(1\)颗棋子放在没有棋子的列上,那么这样会使现在多\(1\)列有\(1\)个棋子的列,那么原来比现在要少\(1\),也就是可以从\(f[i-1][j-1][k]\)转移过来,但是在原来的状态上,有\(m-(j-1)-k\)列是没有棋子的,也就是这几列上都是可以放棋子,根据乘法原理得到转移方程就是:\(f[i][j][k]+=f[i-1][j-1][k]*(m-(j-1)-k)\)。
  • \(1\)颗棋子放在有1个棋子的列上,那么就会让减少原来的有\(1\)个棋子的列,增加一个\(2\)个棋子的列,也就是说原来有\(j+1\)列1个棋子的列,有\(k-1\)个2个棋子的列,得到转移方程就是\(f[i][j][k]+=f[i-1][j+1][k-1]*(j+1)\)。

第三种是放一个\(2\)个棋子:

  • \(1\)颗棋子放在没有棋子的列上,\(1\)颗棋子放在有\(1\)个棋子的列上,那么很明显这样原来的状态就是\(f[i-1][j][k-1]\),因为有一列从\(0\)变成了\(1\),有一列从\(1\)变成了\(2\),就相当于是一列从0变成了2,那么转移方程就是:\(f[i][j][k]+=f[i-1][j][k-1]*(m-j-(k-1))\)。
  • \(2\)颗棋子都放在没有棋子的列上,而且两个棋子在不同的列上,那么原来就有\(j-2\)列是只有\(1\)个棋子,可得原来的状态就是\(f[i-1][j-2][k]\),因为不能有在同一列上,那么需要对剩余没有棋子的列进行排列组合,剩下来的点数为\(m-(j-2)-k\),取两个那么就是\(C^{2}_{m-(j-2)-k}\),得到转移方程:\(f[i][j][k]+=f[i-1][j-2][k]*C^{2}_{m-(j-2)-k}\)。
  • \(2\)颗棋子都放在有一个棋子的列上,而且两个棋子不在同一列,那么现在减少了\(2\)个有\(1\)个棋子的列,增加了\(2\)个有\(2\)个棋子的列,推出原来的状态是\(f[i-1][j+2][k-2]\),在此根据排列组合,乘法原理得到转移方程是:\(f[i-1][j+2][k-2]*C^{2}_{j+2}\)。

综上,我们整理一下转移方程:
\[if (k >= 1) f[i][j][k] = (f[i][j][k] + f[i - 1][j + 1][k - 1] * (j + 1))\]
\[if (j >= 1) f[i][j][k] = (f[i][j][k] + f[i - 1][j - 1][k] * (m - (j - 1) - k))\]
\[if (k >= 1) f[i][j][k] = (f[i][j][k] + f[i - 1][j][k - 1] * j * (m - j - (k - 1)))\]
\[if (j >= 2) f[i][j][k] = (f[i][j][k] + f[i - 1][j - 2][k] * calc(m - (j - 2) - k))\]
\[if (k >= 2) f[i][j][k] = (f[i][j][k] + f[i - 1][j + 2][k - 2] * calc(j + 2))\]
其中calc就是求组合数。

ac代码

#include <bits/stdc++.h>
#define ll long long
#define ms(a, b) memset(a, b, sizeof(a))
#define inf 0x3f3f3f3f
#define mod 9999973
#define N 105
using namespace std;
template <typename T>
inline void read(T &x) {
    x = 0; T fl = 1;
    char ch = 0;
    while (ch < '0' || ch > '9') {
        if (ch == '-') fl = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9') {
        x = (x << 1) + (x << 3) + (ch ^ 48);
        ch = getchar();
    }
    x *= fl;
}
ll f[N][N][N];
int n, m;
ll calc(ll x) {
    return (x * (x - 1)) / 2 % mod;
}
int main() {
    read(n); read(m);
    f[0][0][0] = 1ll;
    for (int i = 1; i <= n; i ++) {
        for (int j = 0; j <= m; j ++) {
            for (int k = 0; k <= m - j; k ++) {
                f[i][j][k] = f[i - 1][j][k];
                if (k >= 1) f[i][j][k] = (f[i][j][k] + f[i - 1][j + 1][k - 1] * (j + 1)) % mod;
                if (j >= 1) f[i][j][k] = (f[i][j][k] + f[i - 1][j - 1][k] * (m - (j - 1) - k)) % mod;
                if (k >= 1) f[i][j][k] = (f[i][j][k] + f[i - 1][j][k - 1] * j * (m - j - (k - 1))) % mod;
                if (j >= 2) f[i][j][k] = (f[i][j][k] + f[i - 1][j - 2][k] * calc(m - (j - 2) - k)) % mod;
                if (k >= 2) f[i][j][k] = (f[i][j][k] + f[i - 1][j + 2][k - 2] * calc(j + 2)) % mod;
                f[i][j][k] %= mod;
            }
        }
    }
    ll ans = 0;
    for (int i = 0; i <= m; i ++) {
        for (int j = 0; j <= m ; j ++) {
            ans = (ans + f[n][i][j]) % mod;
        }
    }
    printf("%lld\n", ans);
    return 0;
}

[luogu2051][bzoj1801][AHOI2009]chess中国象棋【动态规划】的更多相关文章

  1. BZOJ1801 [Ahoi2009]chess 中国象棋 动态规划

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1801 题意概括 在N行M列的棋盘上,放若干个炮可以是0个,使得没有任何一个炮可以攻击另一个炮. 请 ...

  2. BZOJ1801 Ahoi2009 chess 中国象棋 【DP+组合计数】*

    BZOJ1801 Ahoi2009 chess 中国象棋 Description 在N行M列的棋盘上,放若干个炮可以是0个,使得没有任何一个炮可以攻击另一个炮. 请问有多少种放置方法,中国像棋中炮的行 ...

  3. BZOJ1801 [Ahoi2009]chess 中国象棋(DP, 计数)

    题目链接 [Ahoi2009]chess 中国象棋 设$f[i][j][k]$为前i行,$j$列放了1个棋子,$k$列放了2个棋子的方案数 分6种情况讨论,依次状态转移. #include <b ...

  4. bzoj1801: [Ahoi2009]chess 中国象棋(DP)

    1801: [Ahoi2009]chess 中国象棋 题目:传送门 题解: 表示自己的DP菜的抠脚 %题解... 定义f[i][j][k]表示前i行 仅有一个棋子的有j列 有两个棋子的有k个 的方案数 ...

  5. BZOJ1801:[Ahoi2009]chess 中国象棋

    Time Limit: 10 Sec  Memory Limit: 64 MB Description 在N行M列的棋盘上,放若干个炮可以是0个,使得没有任何一个炮可以攻击另一个炮. 请问有多少种放置 ...

  6. bzoj1801: [Ahoi2009]chess 中国象棋 dp

    题意:在N行M列的棋盘上,放若干个炮可以是0个,使得没有任何一个炮可以攻击另一个炮. 请问有多少种放置方法,中国像棋中炮的行走方式大家应该很清楚吧. 题解:dp[i][j][k]表示到了第i行,有j列 ...

  7. BZOJ1801 [Ahoi2009]chess 中国象棋 【dp】

    题目 在N行M列的棋盘上,放若干个炮可以是0个,使得没有任何一个炮可以攻击另一个炮. 请问有多少种放置方法,中国像棋中炮的行走方式大家应该很清楚吧. 输入格式 一行包含两个整数N,M,中间用空格分开. ...

  8. bzoj1801[AHOI2009]CHESS中国象棋

    题意:在棋盘上放一些炮使得它们不互相攻击.其实就是一行/一列最多放两个. 50分的数据中n,m至少有一个不超过8,比较直接的想法是对n/m中较小的一维做状态压缩,状态f[i][S1][S2]表示在前i ...

  9. 【BZOJ1801】[Ahoi2009]chess 中国象棋 DP

    [BZOJ1801][Ahoi2009]chess 中国象棋 Description 在N行M列的棋盘上,放若干个炮可以是0个,使得没有任何一个炮可以攻击另一个炮. 请问有多少种放置方法,中国像棋中炮 ...

随机推荐

  1. Python_面向对象_单例模式

    class A(object): pass a1 = A() a2 = A() print(a1 == a2)print(id(a1))print(id(a2)) 结果: False 23257231 ...

  2. stark组件数据库管理软件的总结

      1.stark - 总结 用到的知识点: 1.单例模式 2.继承 3.反射 4.面向对象 5.modelform 1.注册表 单例模式 site = StarkSite() 2.生成url url ...

  3. composer 自动加载 通过classmap自动架子啊

    https://github.com/brady-wang/composer github地址 composer加载自己写的类 放入一个目录下 更改composer.json "autolo ...

  4. PHP中对象是按值传递还是按引用传递?

    1.首先,什么是按值传递和按引用传递? 按值传递就是仅仅把值传递过去,相当于传递的是值的拷贝,而按引用传递传递的是内存的地址. 在 PHP5 中,如果按引用传递,就是将 zval 的地址赋给另一个变量 ...

  5. tomcat启动的时候报错Failed to start component

    在idea中运行tomcat时,遇到异常,异常信息如下: 16-Jan-2018 16:33:37.325 信息 [localhost-startStop-1] org.apache.catalina ...

  6. [FreeBuff]Trojan.Miner.gbq挖矿病毒分析报告

    Trojan.Miner.gbq挖矿病毒分析报告 https://www.freebuf.com/articles/network/196594.html 竟然还有端口转发... 这哥们.. 江民安全 ...

  7. hdu2089_不要62

    不要62 题目大意:给你一个区间,算出该区间里不含62或4的数的个数 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2089 /* // 暴力就可以过了 ...

  8. 在linux上安装spark详细步骤

    在linux上安装spark ,前提要部署了hadoop,并且安装了scala. 提君博客原创 对应版本 >>提君博客原创  http://www.cnblogs.com/tijun/   ...

  9. 名称空间2.0path

    Django 1点几跟2点几的区别 2.0path 是什么路径就是什么路径.第一个参数不再是正则表达式. 转换器 path的分组 <int:year> 匹配正整数 <str:year ...

  10. windos安装maven

    1.下载好maven压缩包,并解压到相应位置,本次安装在D: 2.配置环境变量 MAVEN_HOME=D:\apache-maven-3.0.5 path=%MAVEN_HOME% 3.生成maven ...