洛谷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(6)之文件
一.读写文件 以追加文件内容(a).读(r).写(w),读写(r+)的形式打开文件: f = open('yesterday','a',encoding='utf-8')#文件句柄 #输出一行文件内容 ...
- 学习笔记-AngularJs(二)
在接下来学习angularjs中,我按照的就是之前 学习笔记-AngularJs(一)所讲的目录来搭建一个学习的项目,做一个互联网大佬人物简介的例子,当然也可以使用angualrjs上面提供的官方例子 ...
- 读书笔记 C# 接口中的索引器之浅析
在C#中,可以在类.结构或接口中用this关键字声明索引器,在索引器内部用get或set访问器访问类中集合的某项值.因此可以将索引器看作是类的属性一样去定义.索引器常用定义格式如下: public i ...
- Cracking The Coding Interview5.2
//Given a (decimal - e.g. 3.72) number that is passed in as a string, print the binary representatio ...
- OpenStack之queens版本创建负载均衡器时报错问题!
采用kolla-ansible部署完毕后,创建负载均衡器时会提示如下的报错 解决办法: 修改网络节点的neutron-lbaas-agent容器 进入lbaas容器里 [root@openstack0 ...
- powerdesigner远程连接数据库
1. dabatase-->configure connections 2.新建连接 3.配置TNS连接测试 4.出现异常及处理 Could not Initialize JavaVM! 出现这 ...
- 计算图 graph
tensorflow,tensor就是数据,flow就是流,tensorflow就是数据流 tensorflow是一个用计算图的形式来表示计算的编程系统,所有的数据和计算都会被转化成计算图上的一个节点 ...
- 牛客国庆集训派对Day5 数论之神
题目描述 终于活成了自己讨厌的样子. 这是她们都还没长大的时候发生的故事.那个时候,栗子米也不需要为了所谓的爱情苦恼. 她们可以在夏日的午后,花大把的时间去研究生活中一些琐碎而有趣的事情,比如数论. ...
- [转]linux shell 多线程实现
情景 shell脚本的执行效率虽高,但当任务量巨大时仍然需要较长的时间,尤其是需要执行一大批的命令时.因为默认情况下,shell脚本中的命令是串行执行的.如果这些命令相互之间是独立的,则可以使用“并发 ...
- L253 Work and Pleasure
To be really happy and really safe, one ought to have at least two or three hobbies, and they must a ...