AHOI2009中国象棋
首先以行为阶段,根据象棋的规则,在同一行中,至多只能有两个炮,同理:在同一列中,至多只能有两个炮
思考一个可以覆盖整个状态空间的dp数组:
dp[i]表示到了第i行
接下来我们想:某列中的炮能否通过位运算求得
我们能够发现,可能我们目前在第i行,但是在某个j行的p列有一个炮,我们要知道第i行的第p列能否放置炮。但是j可能与i相差甚远,我们不能直接通过位运算得到,逐行枚举又会耗费大量不必要的时间。
那么我们就干脆将列的状态记录在数组里,我们想我们其实并不关心到第i行时哪一列有1个炮,哪一列有两个炮,我们只需要知道到第i行时,有多少列有1个炮,有多少列有两个炮,剩下的问题我们能够通过枚举状态解决
这样就有了dp数组:
dp[i][j][k]表示到第i行时,有j列有一个炮,k列有两个炮
假设第i行只放一个炮,那么放置的方法数累加(DP方程)就是:
1.这一个炮放在了原来没有炮的位置
dp[i][j][k] += dp[i - 1][j - 1][k] * (m - j - k)
2.这一个炮放在了原来有一个炮的位置
dp[i][j][k] += dp[i - 1][j + 1][k - 1] * j
假设第i行放置了两个炮
1.这一行两个炮都放在了原来没有炮的位置
dp[i][j][k] += dp[i - 1][j - 2][k] * (m - j - k) * (m - j - k - 1) / 2;
2.这一行一个炮放在了原来有一个炮的位置,一个炮放在了原来没有炮的位置
dp[i][j][k] += dp[i - 1][j][k - 1] * (m - j - k) * j
3.这一行的两个炮都放在了原来有一个炮的位置
dp[i][j][k] += dp[i - 1][j + 2][k - 2] * j * (j - 1) / 2;
假设第i行没有放炮
dp[i][j][k] += dp[i - 1][j][k]
=-=??好像没了?接着就是处理一下每种情况能够使用的限制条件
初态:dp[0][0][0] = 1;
末态:Σdp[n][i][j]
恩是的,这是我原本的思路,但我这么写后,不知道为什么就挂了。
挂了!样例都过不了!
于是我毅然决然的把有前驱推当前状态的写法改为了由当前状态推后继状态,然后就...A了.....
方程差别不大,不做修改,直接看代码吧...
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int p = ;
const int maxn = ;
ll f[maxn][maxn][maxn];
int n, m; inline int read() {
int x = , y = ;
char ch = getchar();
while(!isdigit(ch)) {
if(ch == '-') y = -;
ch = getchar();
}
while(isdigit(ch)) {
x = (x << ) + (x << ) + ch - '';
ch = getchar();
}
return x * y;
} inline int count(int k) {
return k * (k - ) / ;} int main() {
memset(f, , sizeof(f));
n = read(), m = read();
f[][][] = ;
for(int i = ; i < n; ++i)
for(int j = ; j <= m; ++j)
for(int k = ; k + j <= m; ++k)
if(f[i][j][k]) {
f[i + ][j][k] = (f[i][j][k] + f[i + ][j][k]) % p;
if(m - j - k >= ) f[i + ][j + ][k] = (f[i + ][j + ][k] + f[i][j][k] * (m - j - k)) % p;
if(j >= ) f[i + ][j - ][k + ] = (f[i + ][j - ][k + ] + f[i][j][k] * j) % p;
if(m - j - k >= ) f[i + ][j + ][k] = (f[i + ][j + ][k] + f[i][j][k] * count(m - j - k)) % p;
if(m - j - k >= && j >= ) f[i + ][j][k + ] = (f[i + ][j][k + ] + f[i][j][k] * (m - j - k) * j) % p;
if(j >= ) f[i + ][j - ][k + ] = (f[i + ][j - ][k + ] + f[i][j][k] * count(j)) % p;
f[i][j][k] %= p;
}
ll ans = ;
for(int i = ; i <= m; ++i)
for(int j = ; j + i <= m; ++j)
ans = (ans + f[n][i][j]) % p;
cout << ans << '\n';
return ;
}
AHOI2009中国象棋的更多相关文章
- 洛谷 P2051 [AHOI2009]中国象棋 解题报告
P2051 [AHOI2009]中国象棋 题目描述 这次小可可想解决的难题和中国象棋有关,在一个N行M列的棋盘上,让你放若干个炮(可以是0个),使得没有一个炮可以攻击到另一个炮,请问有多少种放置方法. ...
- luogu 2051 [AHOI2009]中国象棋
luogu 2051 [AHOI2009]中国象棋 真是一道令人愉♂悦丧心并框的好题... 首先"没有一个炮可以攻击到另一个炮"有个充分条件就是没有三个炮在同一行或同一列.证明:显 ...
- [洛谷P2051] [AHOI2009]中国象棋
洛谷题目链接:[AHOI2009]中国象棋 题目描述 这次小可可想解决的难题和中国象棋有关,在一个N行M列的棋盘上,让你放若干个炮(可以是0个),使得没有一个炮可以攻击到另一个炮,请问有多少种放置方法 ...
- 洛谷 P2051 [AHOI2009]中国象棋 状态压缩思想DP
P2051 [AHOI2009]中国象棋 题意: 给定一个n*m的空棋盘,问合法放置任意多个炮有多少种情况.合法放置的意思是棋子炮不会相互打到. 思路: 这道题我们可以发现因为炮是隔一个棋子可以打出去 ...
- Luogu P2051 [AHOI2009]中国象棋(dp)
P2051 [AHOI2009]中国象棋 题面 题目描述 这次小可可想解决的难题和中国象棋有关,在一个 \(N\) 行 \(M\) 列的棋盘上,让你放若干个炮(可以是 \(0\) 个),使得没有一个炮 ...
- [Luogu P2051] [AHOI2009]中国象棋 (状压DP->网格DP)
题面 传送门:https://www.luogu.org/problemnew/show/P2051 Solution 看到这题,我们不妨先看一下数据范围 30pt:n,m<=6 显然搜索,直接 ...
- P2051 [AHOI2009]中国象棋
题目描述 这次小可可想解决的难题和中国象棋有关,在一个N行M列的棋盘上,让你放若干个炮(可以是0个),使得没有一个炮可以攻击到另一个炮,请问有多少种放置方法.大家肯定很清楚,在中国象棋中炮的行走方式是 ...
- [AHOI2009]中国象棋
题目描述 这次小可可想解决的难题和中国象棋有关,在一个N行M列的棋盘上,让你放若干个炮(可以是0个),使得没有一个炮可以攻击到另一个炮,请问有多少种放置方法.大家肯定很清楚,在中国象棋中炮的行走方式是 ...
- [P2051 [AHOI2009]中国象棋] DP
https://www.luogu.org/problemnew/show/P2051 题目描述 这次小可可想解决的难题和中国象棋有关,在一个N行M列的棋盘上,让你放若干个炮(可以是0个),使得没有一 ...
- BZOJ1801:[AHOI2009]中国象棋——题解
http://www.lydsy.com/JudgeOnline/problem.php?id=1801 https://www.luogu.org/problemnew/show/P2051 这次小 ...
随机推荐
- BZOJ4651 NOI2016网格(割点)
首先显然可以通过孤立角落里的跳蚤使其不连通,所以只要有解答案就不会大于2.同样显然的一点是当且仅当跳蚤数量<=2且连通时无解.做法其实也很显然了:特判无解,若跳蚤不连通输出0,否则看图中是否无割 ...
- hdu 1133 Buy the Ticket (大数+递推)
Buy the Ticket Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)To ...
- ZOJ 3496 Assignment | 二分+有上下界网络流
题目: http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3496 大概意思:给你一个网络,有源汇,在保证最大流的情况下求下面两 ...
- 在linux环境下让java代码生效的步骤
1.kill jboss 2.compile 3.deploy 4.bootstrap jboss.
- jsonArray与jsonObject
最近两个星期接触最多的就是json和map了. 之前用到的json,就是一个键对应一个值,超级简单的一对一关系.现在用到的json那可以层层嵌套啊,刚开始接触的时候,确实有种崩溃的赶脚,不想去理,取个 ...
- rman备份与异机恢复
一.rman备份脚本并为定时任务 #!/bin/bashsource ~/.bash_profileexport LANG=en_USBACKUP_DATE=`date +%d`#RMAN_LOG_F ...
- 用eval转化对象
var str = '{"name": "tom","age": 12,"sex": "man"}' ...
- Java并发(5)- ReentrantLock与AQS
引言 在synchronized未优化之前,我们在编码中使用最多的同步工具类应该是ReentrantLock类,ReentrantLock拥有优化后synchronized关键字的性能,又提供了更多的 ...
- cdp协议通信并发编程基础之进程
一 . 基于UDP的套接字 udp是无链接的所以先启动哪一段都不会报错 udp服务端 import socket server=socket.socket(socket.AF_INET,socket. ...
- algorithm ch6 priority queque
堆数据结构的一个重要用处就是:最为高效的优先级队列.优先级队列分为最大优先级队列和最小优先级队列,其中最大优先级队列的一个应用实在一台分时计算机上进行作业的调度.当用堆来实现优先级队列时,需要在队中的 ...