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

    题目描述 给一个长度为n的数列,我们需要找出该数列的一个子串,使得子串平均数最大化,并且子串长度>=m. 输入输出格式 输入格式: N+1行, 第一行两个整数n和m 接下来n行,每行一个整数a[ ...

  2. AGC017D Game on Tree(树型博弈)

    题目大意: 给出一棵n个结点的树,以1为根,每次可以切掉除1外的任意一棵子树,最后不能切的话就为负,问是先手必胜还是后手必胜. 题解: 首先我们考虑利用SG函数解决这个问题 如果1结点有多个子节点,那 ...

  3. hdu4035 Maze 【期望dp + 数学】

    题目链接 BZOJ4035 题解 神题啊...orz 不过网上题解好难看,数学推导不写\(Latex\)怎么看..[Latex中毒晚期] 我们由题当然能很快写出\(dp\)方程 设\(f[i]\)表示 ...

  4. vector 搜索

    http://classfoo.com/ccby/article/cIBahI #include <iostream> #include <algorithm> #includ ...

  5. shell里的getopts

    By francis_hao    Jul 5,2017   getopts是shell的一个内置命令. 概述 getopts optstring name [args]OPTIND,OPTARG,O ...

  6. yaf的安装

    http://kenby.iteye.com/blog/1979899 yaf源码分析学习网站 # wget https://github.com/laruence/php-yaf/archive/m ...

  7. JS中二维数组的声明

    var myarr=new Array(); //先声明一维 for(var i=0;i<2;i++){ //一维长度为2 myarr[i]=new Array(); //再声明二维 for(v ...

  8. MAVEN 编译打包测试 指定本地jar

    转载自:http://penuel.iteye.com/blog/1766102 maven对于互联网开发,进行版本管理有着不可或缺的作用;  而经常开发的程序猿直接联调或者依赖未上线或deploy的 ...

  9. 【BZOJ2286】【SDOI2011】消耗战 [虚树][树形DP]

    消耗战 Time Limit: 20 Sec  Memory Limit: 512 MB[Submit][Status][Discuss] Description 在一场战争中,战场由n个岛屿和n-1 ...

  10. bzoj3779: 重组病毒 link-cut-tree

    题目传送门 这道题看了做了个神转换.....推荐个博客给各位大爷看看吧神犇传送门 代码敲了半天....题目也读了半天 线段树维护的东西很容易和lct混在一起 调了调能过也是很开心啊 运气比较好吧233 ...