洛谷P2051 中国象棋(dp)
题目链接:传送门
题目大意:
在N行M列的棋盘中放象棋中的“炮”,问要使得“炮”两两互不伤害,有多少种放法。
1 ≤ n,m ≤ 100,答案对9999973取模。
思路:
按行更新答案。每行炮可以放在空列(下称A列)和有一个炮的列(下称B列),从而生成B列和有两个炮的列(C列),所以更新行的时候有这样几种选择:
①不放“炮”;
②选一个A列放一个“炮”,生成一个B列;
③选一个B列放一个“炮”,生成一个C列;
④选两个A列放一个“炮”,生成两个B列;
⑤选两个B列放一个“炮”,生成两个C列;
⑥选一个A列和一个B列各放一个“炮”,生成一个B列和一个C列;(注意在同一行不能放两个棋子在同一列,所以不能看作用一个A列生成一个C列)
考虑到各行各列的顺序与答案无关:
状态:
f[i][j][k]:第i行有j个B列和k个C列。
初始状态:
f[0][0][0] = 1;
状态转移方程:
①f[i][j][k] = f[i-1][j][k];
②f[i][j][k] = f[i-1][j-1][k] ×(i-1行A列个数);
③f[i][j][k] = f[i-1][j+1][k-1] ×(i-1行B列个数);
④f[i][j][k] = f[i-1][j-2][k] ×(i-1行A列个数选2);
⑤f[i][j][k] = f[i-1][j+2][k-2] ×(i-1行B列个数选2);
⑥f[i][j][k] = f[i-1][j][k-1] ×(i-1行A列个数)×(i-1行B列个数);
注意边界和取模即可。
时间复杂度:O(nm2)
#include <bits/stdc++.h> using namespace std;
typedef long long ll;
const int MAX_N = ;
const int MOD = ; ll f[MAX_N][MAX_N][MAX_N]; inline int C(int n)
{//n选2
return n*(n-)/;
} int main()
{
int N, M;
cin >> N >> M;
f[][][] = ;
for (int i = ; i <= N; i++) {
for (int j = ; j <= M; j++) {
for (int k = ; k+j <= M; k++) {
//放1个
if (j- >= && (M-(j-+k)) >= )
f[i][j][k] = (f[i][j][k] + f[i-][j-][k] * (M-(j-+k))) % MOD;
if (j+ <= M && k >= )
f[i][j][k] = (f[i][j][k] + f[i-][j+][k-] * (j+)) % MOD;
//放两个
if (j- >= && (M-(j-+k)) >= )
f[i][j][k] = (f[i][j][k] + f[i-][j-][k] * C(M-(j-+k))) % MOD;
if (k >= && (M-(j+k-)) >= && j >= )
f[i][j][k] = (f[i][j][k] + f[i-][j][k-] * (M-(j+k-)) * j) % MOD;
if (k >= )
f[i][j][k] = (f[i][j][k] + f[i-][j+][k-] * C(j+)) % MOD;
//不放
f[i][j][k] = (f[i][j][k] + f[i-][j][k]) % MOD;
}
}
}
ll ans = ;
for (int j = ; j <= M; j++)
for (int k = ; k+j <= M; k++)
ans = (ans + f[N][j][k]) % MOD;
cout << ans << endl;
return ;
}
洛谷P2051 中国象棋(dp)的更多相关文章
- 洛谷P2051 中国象棋
题目描述 这次小可可想解决的难题和中国象棋有关,在一个N行M列的棋盘上,让你放若干个炮(可以是0个),使得没有一个炮可以攻击到另一个炮,请问有多少种放置方法.大家肯定很清楚,在中国象棋中炮的行走方式是 ...
- 洛谷 - P2051 - 中国象棋 - 简单dp
https://www.luogu.org/problemnew/show/P2051 一点都不简单的简单dp. 还是从旧行转移到新行,而不是考虑新行从哪些旧行转移吧. #include<bit ...
- 洛谷P2051 中国象棋【dp】
题目:https://www.luogu.org/problemnew/show/P2051 题意:n*m的格子里放炮,使他们不能互相攻击. 如果两个炮在同一行同一列并且中间还有一个棋子的话就可以攻击 ...
- 洛谷 [P2051] 中国象棋
DP orz__stdcall 首先要想出来,每行最多只能放两个棋子,这是显然的 于是决策就是一行一行地处理 30分的做法就是裸的枚举,暴搜,枚举这一行放哪里,放几个 然后想到了压位dp,按3进制表示 ...
- 洛谷 P2051 中国象棋 题解
题面 状态可能不太好想,设f[i][j][k]表示前i行其中有j行是放一个炮,有k行是放两个炮的合法方案数: 那么: f[i+1][j][k]+=f[i][j][k] 在这一行不放任何棋子: ...
- P2051 中国象棋
P2051 中国象棋 题目描述 这次小可可想解决的难题和中国象棋有关,在一个N行M列的棋盘上,让你放若干个炮(可以是0个),使得没有一个炮可以攻击到另一个炮,请问有多少种放置方法.大家肯定很清楚,在中 ...
- 洛谷 P2051 [AHOI2009]中国象棋 状态压缩思想DP
P2051 [AHOI2009]中国象棋 题意: 给定一个n*m的空棋盘,问合法放置任意多个炮有多少种情况.合法放置的意思是棋子炮不会相互打到. 思路: 这道题我们可以发现因为炮是隔一个棋子可以打出去 ...
- [洛谷P2051] [AHOI2009]中国象棋
洛谷题目链接:[AHOI2009]中国象棋 题目描述 这次小可可想解决的难题和中国象棋有关,在一个N行M列的棋盘上,让你放若干个炮(可以是0个),使得没有一个炮可以攻击到另一个炮,请问有多少种放置方法 ...
- 洛谷 P2051 [AHOI2009]中国象棋 解题报告
P2051 [AHOI2009]中国象棋 题目描述 这次小可可想解决的难题和中国象棋有关,在一个N行M列的棋盘上,让你放若干个炮(可以是0个),使得没有一个炮可以攻击到另一个炮,请问有多少种放置方法. ...
随机推荐
- python列表反转函数
def reverse(ListInput): RevList=[] for i in range (len(ListInput)): RevList.append(ListInput.pop()) ...
- possible error
1● regedit 2● path [HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\Windows Error Reporting] 3● 步 ...
- js如何通过末次月经日期计算预产日期
计算方式有两种 1)直接添加280天 2)添加10月8天(参数传递,可用改成9月7天等) js中引入文件 <script src="js/jquery.min.js"> ...
- LaTeX技巧10:LaTeX数学公式输入初级入门
LaTeX最强大的功能就是显示美丽的数学公式,下面我们来看这些公式是怎么实现的. 1.数学公式的前后要加上 $ 或 \( 和 \),比如:$f(x) = 3x + 7$ 和 \(f(x) = 3x + ...
- Java Web(一) 前言及体系结构
Web应用程序 Web程序是什么 Web应用程序就是一般所说的网站,由服务器,客户端浏览器以及网络组成.但Web程序又不是一般意义的网站,一般的网站是提供信息服务,重在内容,程序往往比较简单,但商用的 ...
- oo作业总结(一)
概述 经历了三次oo作业的洗礼,让我对java语言的强大以及面向对象编程有了初步的理解(当然,我是小白).本文接下来就将对自己这三次作业的代码进行分析以及分享自己的心路历程. 基础知识点考核 针对前三 ...
- uiautomator2 获取APP Toast内容
前言:appium必须是1.6以上的版本 环境(安装和安装都可以运行成功,我也不确定要不要这个): 1.抓到toast需要安装uiautomator2,安装npm:npm install -g cnp ...
- L298 猴子进化过程
The evolution of monkeys remains a mystery Why monkeys and apes took separate evolutionary paths has ...
- 四、使用汇编编写LED裸机驱动
1. 确定硬件连接 打开OK6410底板电路图,找到LED,可以发现NLEDx为0时LED点亮. 找到LED的控制引脚,发现LED控制引脚通过连接器连到了核心板: 打开核心板电路图,找到对应的连接器中 ...
- MySQL:数据表基本操作
数据表基本操作 注意点: 1.数据表中已经有数据时,轻易修改数据类型,有可能因为不同的数据类型的数据在机器 中存储的方式及长度并不相同,修改数据类型可能会影响到数据表中已有的数据类型. 2. 数据表 ...