[luogu2051][bzoj1801][AHOI2009]chess中国象棋【动态规划】
题目描述
这次小可可想解决的难题和中国象棋有关,在一个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中国象棋【动态规划】的更多相关文章
- BZOJ1801 [Ahoi2009]chess 中国象棋 动态规划
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1801 题意概括 在N行M列的棋盘上,放若干个炮可以是0个,使得没有任何一个炮可以攻击另一个炮. 请 ...
- BZOJ1801 Ahoi2009 chess 中国象棋 【DP+组合计数】*
BZOJ1801 Ahoi2009 chess 中国象棋 Description 在N行M列的棋盘上,放若干个炮可以是0个,使得没有任何一个炮可以攻击另一个炮. 请问有多少种放置方法,中国像棋中炮的行 ...
- BZOJ1801 [Ahoi2009]chess 中国象棋(DP, 计数)
题目链接 [Ahoi2009]chess 中国象棋 设$f[i][j][k]$为前i行,$j$列放了1个棋子,$k$列放了2个棋子的方案数 分6种情况讨论,依次状态转移. #include <b ...
- bzoj1801: [Ahoi2009]chess 中国象棋(DP)
1801: [Ahoi2009]chess 中国象棋 题目:传送门 题解: 表示自己的DP菜的抠脚 %题解... 定义f[i][j][k]表示前i行 仅有一个棋子的有j列 有两个棋子的有k个 的方案数 ...
- BZOJ1801:[Ahoi2009]chess 中国象棋
Time Limit: 10 Sec Memory Limit: 64 MB Description 在N行M列的棋盘上,放若干个炮可以是0个,使得没有任何一个炮可以攻击另一个炮. 请问有多少种放置 ...
- bzoj1801: [Ahoi2009]chess 中国象棋 dp
题意:在N行M列的棋盘上,放若干个炮可以是0个,使得没有任何一个炮可以攻击另一个炮. 请问有多少种放置方法,中国像棋中炮的行走方式大家应该很清楚吧. 题解:dp[i][j][k]表示到了第i行,有j列 ...
- BZOJ1801 [Ahoi2009]chess 中国象棋 【dp】
题目 在N行M列的棋盘上,放若干个炮可以是0个,使得没有任何一个炮可以攻击另一个炮. 请问有多少种放置方法,中国像棋中炮的行走方式大家应该很清楚吧. 输入格式 一行包含两个整数N,M,中间用空格分开. ...
- bzoj1801[AHOI2009]CHESS中国象棋
题意:在棋盘上放一些炮使得它们不互相攻击.其实就是一行/一列最多放两个. 50分的数据中n,m至少有一个不超过8,比较直接的想法是对n/m中较小的一维做状态压缩,状态f[i][S1][S2]表示在前i ...
- 【BZOJ1801】[Ahoi2009]chess 中国象棋 DP
[BZOJ1801][Ahoi2009]chess 中国象棋 Description 在N行M列的棋盘上,放若干个炮可以是0个,使得没有任何一个炮可以攻击另一个炮. 请问有多少种放置方法,中国像棋中炮 ...
随机推荐
- Python_面向对象_单例模式
class A(object): pass a1 = A() a2 = A() print(a1 == a2)print(id(a1))print(id(a2)) 结果: False 23257231 ...
- stark组件数据库管理软件的总结
1.stark - 总结 用到的知识点: 1.单例模式 2.继承 3.反射 4.面向对象 5.modelform 1.注册表 单例模式 site = StarkSite() 2.生成url url ...
- composer 自动加载 通过classmap自动架子啊
https://github.com/brady-wang/composer github地址 composer加载自己写的类 放入一个目录下 更改composer.json "autolo ...
- PHP中对象是按值传递还是按引用传递?
1.首先,什么是按值传递和按引用传递? 按值传递就是仅仅把值传递过去,相当于传递的是值的拷贝,而按引用传递传递的是内存的地址. 在 PHP5 中,如果按引用传递,就是将 zval 的地址赋给另一个变量 ...
- tomcat启动的时候报错Failed to start component
在idea中运行tomcat时,遇到异常,异常信息如下: 16-Jan-2018 16:33:37.325 信息 [localhost-startStop-1] org.apache.catalina ...
- [FreeBuff]Trojan.Miner.gbq挖矿病毒分析报告
Trojan.Miner.gbq挖矿病毒分析报告 https://www.freebuf.com/articles/network/196594.html 竟然还有端口转发... 这哥们.. 江民安全 ...
- hdu2089_不要62
不要62 题目大意:给你一个区间,算出该区间里不含62或4的数的个数 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2089 /* // 暴力就可以过了 ...
- 在linux上安装spark详细步骤
在linux上安装spark ,前提要部署了hadoop,并且安装了scala. 提君博客原创 对应版本 >>提君博客原创 http://www.cnblogs.com/tijun/ ...
- 名称空间2.0path
Django 1点几跟2点几的区别 2.0path 是什么路径就是什么路径.第一个参数不再是正则表达式. 转换器 path的分组 <int:year> 匹配正整数 <str:year ...
- windos安装maven
1.下载好maven压缩包,并解压到相应位置,本次安装在D: 2.配置环境变量 MAVEN_HOME=D:\apache-maven-3.0.5 path=%MAVEN_HOME% 3.生成maven ...