首先以行为阶段,根据象棋的规则,在同一行中,至多只能有两个炮,同理:在同一列中,至多只能有两个炮
思考一个可以覆盖整个状态空间的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中国象棋的更多相关文章

  1. 洛谷 P2051 [AHOI2009]中国象棋 解题报告

    P2051 [AHOI2009]中国象棋 题目描述 这次小可可想解决的难题和中国象棋有关,在一个N行M列的棋盘上,让你放若干个炮(可以是0个),使得没有一个炮可以攻击到另一个炮,请问有多少种放置方法. ...

  2. luogu 2051 [AHOI2009]中国象棋

    luogu 2051 [AHOI2009]中国象棋 真是一道令人愉♂悦丧心并框的好题... 首先"没有一个炮可以攻击到另一个炮"有个充分条件就是没有三个炮在同一行或同一列.证明:显 ...

  3. [洛谷P2051] [AHOI2009]中国象棋

    洛谷题目链接:[AHOI2009]中国象棋 题目描述 这次小可可想解决的难题和中国象棋有关,在一个N行M列的棋盘上,让你放若干个炮(可以是0个),使得没有一个炮可以攻击到另一个炮,请问有多少种放置方法 ...

  4. 洛谷 P2051 [AHOI2009]中国象棋 状态压缩思想DP

    P2051 [AHOI2009]中国象棋 题意: 给定一个n*m的空棋盘,问合法放置任意多个炮有多少种情况.合法放置的意思是棋子炮不会相互打到. 思路: 这道题我们可以发现因为炮是隔一个棋子可以打出去 ...

  5. Luogu P2051 [AHOI2009]中国象棋(dp)

    P2051 [AHOI2009]中国象棋 题面 题目描述 这次小可可想解决的难题和中国象棋有关,在一个 \(N\) 行 \(M\) 列的棋盘上,让你放若干个炮(可以是 \(0\) 个),使得没有一个炮 ...

  6. [Luogu P2051] [AHOI2009]中国象棋 (状压DP->网格DP)

    题面 传送门:https://www.luogu.org/problemnew/show/P2051 Solution 看到这题,我们不妨先看一下数据范围 30pt:n,m<=6 显然搜索,直接 ...

  7. P2051 [AHOI2009]中国象棋

    题目描述 这次小可可想解决的难题和中国象棋有关,在一个N行M列的棋盘上,让你放若干个炮(可以是0个),使得没有一个炮可以攻击到另一个炮,请问有多少种放置方法.大家肯定很清楚,在中国象棋中炮的行走方式是 ...

  8. [AHOI2009]中国象棋

    题目描述 这次小可可想解决的难题和中国象棋有关,在一个N行M列的棋盘上,让你放若干个炮(可以是0个),使得没有一个炮可以攻击到另一个炮,请问有多少种放置方法.大家肯定很清楚,在中国象棋中炮的行走方式是 ...

  9. [P2051 [AHOI2009]中国象棋] DP

    https://www.luogu.org/problemnew/show/P2051 题目描述 这次小可可想解决的难题和中国象棋有关,在一个N行M列的棋盘上,让你放若干个炮(可以是0个),使得没有一 ...

  10. BZOJ1801:[AHOI2009]中国象棋——题解

    http://www.lydsy.com/JudgeOnline/problem.php?id=1801 https://www.luogu.org/problemnew/show/P2051 这次小 ...

随机推荐

  1. Topcoder SRM579 1000pts

    石头剪刀布QAQ 一看是个很油的概率dp 首先一看你很快能得出状态的表示F[i][r][p][s] 然后只要考虑r,p,s出现的次数来进行概率dp就好了 具体实现的时候细节很多(少) 如果预处理一下组 ...

  2. 近期对于windows服务的理解

    1.APP.config的作用   在开发环境下时,根目录下的APP.config里面会填写一些参数之类的.当生成之后,这些参数将会被自动生成在*.exe文件目录中.如图: 其中,.exe文件为Win ...

  3. hive对有特殊值null的数据倾斜处理

    对有特殊值的数据倾斜处理 SET mapred.reduce.tasks=20;SET hive.map.aggr=TRUE;SET hive.groupby.skewindata=TRUE;SET ...

  4. Hibernate 懒加载 错误----no session

    错误: unable to evaluate the expression Method threw 'org.hibernate.LazyInitializa org.hibernate.LazyI ...

  5. LOJ 6057 - [HNOI2016]序列 加强版再加强版

    Description 给定一个长度为 \(n\le 3*10^6\) 的序列 \(q\le 10^7\) 次询问每次求区间 \([l,r]\) 的所有子区间的最小值的和 询问随机 Solution ...

  6. HDU2546饭卡---(DP 经典背包)

    http://acm.hdu.edu.cn/showproblem.php?pid=2546 饭卡 Time Limit: 5000/1000 MS (Java/Others)    Memory L ...

  7. 图论:2-SAT

    先象征性地描述一下问题:一组(或者一个)东西有且仅有两种选择,要么选这个,要么选那个,还有一堆的约束条件 图论问题,当然是建边跑图喽 给出模型: 模型一:两者(A,B)不能同时取 那么选择了A就只能选 ...

  8. codevs3160 最长公共子串

    传送门:http://codevs.cn/problem/3160/ [题解] CTSC前复习模板 sa的模板..记住基数排序就够了(还有height) 还有就是sa[i]表示排名为i的后缀是啥..r ...

  9. 【洛谷 P1651】 塔 (差值DP)

    题目链接 题意:\(n\)个木块放到两个塔里,每个木块可放可不放,使得两塔高度相同且高度最大,求最大高度. 这个差值\(DP\)的思维难度还是很大的,没想出来,我就打了一个\(dfs\)骗了好像\(2 ...

  10. Intellij IDEA创建spring MVC项目

    相信各位未来的Java工程师已经接触到了spring MVC这个框架的强大之处,看了很多的教程,都是eclipse的,在intellij IDEA这个强大的工具面前居然不能很顺畅的,今天我就带领大家用 ...