题目描述

这次小可可想解决的难题和中国象棋有关,在一个N行M列的棋盘上,让你放若干个炮(可以是0个),使得没有一个炮可以攻击到另一个炮,请问有多少种放置方法。大家肯定很清楚,在中国象棋中炮的行走方式是:一个炮攻击到另一个炮,当且仅当它们在同一行或同一列中,且它们之间恰好 有一个棋子。你也来和小可可一起锻炼一下思维吧!

40pts

考试遇到了这个题,玄学打表得了\(40pts\)

玄学打表吼啊

xjb分析

正解竟然是个\(DP\)? 还有人说是状压\(DP\)?哪里来的状压啊!

前置知识

考虑到我们的合法状态的话,每一行每一列的炮的数量\(\le 2\)

(炮打隔重山?) 显然 如果一行或者一列有三个炮的话将会不合法.(两个炮可以互相打啊 qwq)

如何设状态?

因为每一行每一列的炮的数量\(\leq 2\)

所以我们考虑记数组去存储有几列放了一个炮,有几列放了两个炮.

我们又需要考虑转移?

因此设出状态

  \(f[i][j][k]\)代表放了前\(i\)行,有\(j\)列是有一个棋子,有\(k\)列是有2个棋子的合法方案数.

这个时候我们知道全部的列数,又知道一些情况的列数.

所以我们可以求出不放棋子的列数

单步容斥:空的=全部的\(-\)合法的

空的序列\(=m-j-k\)

确定情况

  1. 我们可以在当前第\(i\)行不放棋子.
  2. 我们可以在当前第\(i\)行放一个棋子
  3. 我们可以在当前第\(i\)行放两个棋子.

接下来就需要分类讨论这些情况.

分类讨论

一.不放棋子

我们可以直接继承上面的状态.即

\[f[i][j][k]=f[i-1][j][k]
\]

二.放一个棋子

显然我们不会选择放在有两个棋子的列.

因此存在情况如下

\[\begin{cases}放在有一个棋子的列 f[i][j][k]+=f[i-1][j+1][k-1]\times (j+1) \\\\\\ 放在没有棋子的列 f[i][j][k]+=f[i-1][j-1][k]\times (m-(j-1)-k)\end{cases}
\]

解释:
放在一个棋子的列

我们在某一个有一个棋子列放置棋子,会使这一列变为有两个棋子.

即我们要得到\(f[i][j][k]\)需要在\(j+1\)个有一个棋子的列放置棋子,变为\(j\)个有一个棋子的列

而我们又会得到一个新的有两个棋子的列.因此我们之前必须有\(k-1\)个有两个棋子的列.

即\(f[i-1][j+1][k-1]\)的状态可以传递给\(f[i][j][k]\)

而我们又可以在\((j+1)\)中的任何一列放置这一个棋子.

因此我们要\(\times (j+1)\)

放在没有棋子的列

在一个没有棋子的列放置棋子,我们会得到一个新的有一个棋子的列.

即我们要从\(j-1\)得到\(j\).

而这个时候,我们有两个棋子的列的数量不会变,所以从\(k\)传递即可.

即\(f[i-1][j-1][k]\)的状态可以传递给\(f[i][j][k]\)

又因为我在空列中的任何一列放置这个棋子.

所以要$\times $$(m-(j-1)-k)$

三.放两个棋子

这个时候情况会多一个.先请大家自己考虑一下.

这个时候存在情况如下

\[\begin{cases}一个放在有一个棋子的列,另一个放在没有棋子的列 f[i][j][k]+=f[i-1][j][k-1]\times j \times (m-j-(k-1)) \\\\ 都放在没有棋子的列 f[i][j][k]+=f[i-1][j-2][k]\times C_{m-(j-2)-k}^{2}\\\\ 都放在有一个棋子的列 f[i][j][k]+=f[i-1][j+2][k-2] \times C_{j+2}^{2}\end{cases}
\]

解释
一个放在有一个棋子的列,一个放在没有棋子的列

这个时候,我们放置之后 :

一个没有棋子的列会变成一个有一个棋子的列,而一个有一个棋子的列会变成一个有两个棋子的列。

此时我们发现,

​ 有一个棋子的列的数量不会变,因此第二维依旧为\(j\),

​ 又因为我们会新增一个有两个棋子的列,所以我们需要从\(k-1\)转移过来.

又因为我们可以在有一个棋子的列随便放,空列随便放.

根据乘法原理,需要\(\times j \times (m-j-(k-1))\)

都放在没有棋子的列

此时我们放置之后

​ 会增加两个新的有一个棋子的列.

因此我们需要从\(j-2\)转移过来.

而两个棋子的列的数量并不会改变,所以依旧为\(k\)

又因为在空列中我们随便放.

根据组合数学,需要\(\times C_{m-(j-2)-k}^{2}\)

都放在有一个棋子的列

我们放置在有一个棋子的列之后:

​ 这两个有一个棋子的列都会变成有两个子的列.

​ 即\(j+2\)变成\(j\),从\(k-2\)变成\(k\)

又因为这些有一个棋子的列我们随便选择.

根据组合数学,需要\(\times C_{j+2}^{2}\)

分析完毕

我们需要接下来做的就是判断边界,一定要判断!!(血的教训!

代码

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cctype>
#include<cstring>
#define mod 9999973
#define int long long
#define R register
using namespace std;
inline void in(int &x)
{
int f=1;x=0;char s=getchar();
while(!isdigit(s)){if(s=='-')f=-1;s=getchar();}
while(isdigit(s)){x=x*10+s-'0';s=getchar();}
x*=f;
}
int n,m,ans;
int f[108][108][108];
inline int C(int x)
{
return ((x*(x-1))/2)%mod;
}
signed main()
{
in(n),in(m);
f[0][0][0]=1;
for(R int i=1;i<=n;i++)
{
for(R int j=0;j<=m;j++)
{
for(R int k=0;k<=m-j;k++)
{
f[i][j][k]=f[i-1][j][k];
if(k>=1)(f[i][j][k]+=f[i-1][j+1][k-1]*(j+1));
if(j>=1)(f[i][j][k]+=f[i-1][j-1][k]*(m-j-k+1));
if(k>=2)(f[i][j][k]+=f[i-1][j+2][k-2]*(((j+2)*(j+1))/2));
if(k>=1)(f[i][j][k]+=f[i-1][j][k-1]*j*(m-j-k+1));
if(j>=2)(f[i][j][k]+=f[i-1][j-2][k]*C(m-j-k+2));
f[i][j][k]%=mod;
}
}
}
for(R int i=0;i<=m;i++)
for(R int j=0;j<=m;j++)
(ans+=f[n][i][j])%=mod;
printf("%lld",(ans+mod)%mod);
}

DP【p2051(bzoj 1801)】 [AHOI2009]中国象棋.的更多相关文章

  1. BZOJ 1801 AHOI2009 中国象棋 递归

    标题效果:给定一个棋盘.放置一些枪.它需要随机两支枪不能互相攻击,评估的数目p模值 首先,两炮不攻击对方自由地等同于一条线最多可有只有两个枪 直形压力DP话是50分 考虑到每个列是等效 然后我们就可以 ...

  2. BZOJ 1801: [Ahoi2009]中国象棋

    题目描述 //每行每列最多放两个,可以讨论第i-1行到第i行的每一种情况 #include<complex> #include<cstdio> using namespace ...

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

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

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

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

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

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

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

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

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

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

  8. luogu 2051 [AHOI2009]中国象棋

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

  9. BZOJ 1801: [Ahoi2009]chess 中国象棋( dp )

    dp(i, j, k)表示考虑了前i行, 放了0个炮的有j列, 放了1个炮的有k列. 时间复杂度O(NM^2) -------------------------------------------- ...

随机推荐

  1. java中封装的概念

    封装(Encapsulation)是类的三大特性之一, 就是将类的状态信息隐藏在类的内部,不允许外部程序直接访问, 而是通过该类提供的方法来实现对隐藏信息的操作和访问. 简而言之,就是隐藏内部实现,提 ...

  2. 2.0 python+appium环境搭建

    Python下载地址:链接:https://pan.baidu.com/s/1Z3H8tw8AiBVwpxdcABC7XQ 密码:z66t Pycharm下载地址: 链接:https://pan.ba ...

  3. ExtJS Ext.MessageBox.alert()弹出对话框详解

    Ext.MessageBox是一个工具类,他继承自Obiect对象,用来生成各种风格的信息提示对话框,Ext.Msg是该类的别名,使用Ext.MessageBox和用Ext.Msg效果是一样的,而后者 ...

  4. ALPHA(10)

    目录 组员情况 组员1(组长):胡绪佩 组员2:胡青元 组员3:庄卉 组员4:家灿 组员5:凯琳 组员6:翟丹丹 组员7:何家伟 组员8:政演 组员9:黄鸿杰 组员10:刘一好 组员11:何宇恒 展示 ...

  5. android瀑布流照片墙实现代码详解

    照片墙的实现,是需要往手机里面添加很多图片的,如果没有对资源进行合理的释放,程序很快就会出现OOM.所以需要用到LruCache算法来缓存图片. 1,首先是图片资源类,这个类中包含了很多图片链接. p ...

  6. CSS使用示例

    CSS的存在就是将网页的内容与内容展示的方式进行了分离. 使用CSS的方式有好几种,最常用的是通过引入外部CSS文件进行使用 HTML <!DOCTYPE html> <html&g ...

  7. BZOJ 2438:杀人游戏(tarjan+概率)

    杀人游戏Description一位冷血的杀手潜入 Na-wiat,并假装成平民.警察希望能在 N 个人里面,查出谁是杀手. 警察能够对每一个人进行查证,假如查证的对象是平民,他会告诉警察,他认识的人, ...

  8. Windows 2008 R2无法打补丁

    遇到了Windows 2008 R2无法打补丁,并且控制台上的feature和roles都是error 可下载这个补丁进行修复: System Update Readiness Tool for Wi ...

  9. nginx tomcat负载均衡 使用redis session共享

    环境准备 1.准备一台nginx服务器 ip192.168.1.133 端口81 安装过程: #首先安装依赖: yum -y install gcc-c++ yum -y install pcre p ...

  10. 解决hibernate向mysql插入中文乱码问题(更改MySQL字符集)

    1.首先需要修改mysql数据库的配置文件my.ini,此文件放在mysql根目录下.在此文件下查找default-character-set属性,并将其值更改为utf8(注意:不是utf-8,也要注 ...