[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个,使得没有任何一个炮可以攻击另一个炮. 请问有多少种放置方法,中国像棋中炮 ...
随机推荐
- rest-framework的权限组件
权限组件 写在开头: 首先要在models表中添加一个用户类型的字段: class User(models.Model): name=models.CharField(max_length=32) p ...
- 【学习总结】C-翁恺老师-入门-总
2019-1-2 翁恺老师C入门视频-启程 代码详见GitHub: 目录 第0周:程序设计与C语言 第1周:计算 第2周:判断 第3周:循环 第4周:循环控制 第5周:数据类型 第6周:函数 第7周: ...
- 简单封装mongodb
首先安装mongodb npm i mongodb --save 简单封装,在modules目录下新建db.js var MongoClient=require('mongodb').MongoCl ...
- 1228.Poor Pigs 可怜的猪
转自[LeetCode] Poor Pigs 可怜的猪 There are 1000 buckets, one and only one of them contains poison, the re ...
- embed标签的flash层级太高问题
因为客户要求,项目得兼容IE的兼容模式 页面到了flash都会遮挡底部悬浮的导航. 改变浮动窗口和embed的层级还是不可以.应该不是层级的关系. 最后百度解决方案:在embed标签内添加了wmode ...
- flutter开发vscode用模拟器调试
android studio的太重,我装的是android sdk,使用avd的模拟器启动黑屏 启动夜神模拟器(已卸载) 建立连接: adb connect 127.0.0.1:62001 (夜 ...
- “耐撕”团队 2016.03.31 站立会议
1. 时间: 19:30--19:50 共计20分钟. 2. 成员: Z 郑蕊 * 组长 (博客:http://www.cnblogs.com/zhengrui0452/), P 濮成林(博客:ht ...
- GlusterFS 安装配置
1.磁盘格式化 mkfs.xfs -i size=512 /dev/vdb1 mkdir -p /data/brick1 cat > /etc/fstab <<EOF /dev/vd ...
- spring boot 获取bean
在写测试用例的时候,如果是springboot的应该加上 springboot的标签: @SpringBootTest(classes = ApplicationLoader.class) @Acti ...
- 设计模式笔记:简单工厂模式(Simple Factory)
1. 简单工厂模式简介 1.1 定义 简单工厂模式:定义一个Factory类,可以根据参数的不同返回不同类的实例,被创建的实例通常有共同的父类. 简单工厂模式:只需要一个Factory类. 简单工厂模 ...