[Luogu P2051] [AHOI2009]中国象棋 (状压DP->网格DP)
题面
传送门:https://www.luogu.org/problemnew/show/P2051


Solution
看到这题,我们不妨先看一下数据范围
30pt:n,m<=6
显然搜索,直接爆搜水过
复杂度O(n^m(吧))
50pt: n<=100,m<=8
是状压/网络流的复杂度
当然,这题显然是状压
由题可以得出一个很显然但很重要的废话:每行每列只能放0~2个棋子
因此,我们可以考虑写一个3进制的状压DP
设f[i][j]表示第 i 行,每一列的具体情况以三进制的表达形式存在j里 的方案数
转移也很显然
分类转移一下
当前这一行放了0个棋子 f[i][j]+=f[i-1][j]
当前这一行放了1个棋子, 枚举一下有可能放的位置k f[i][j]+=xigema f[i-1][k]
当前这一行放了2个棋子 ,枚举一下那两个有可能放的位置,最后表达成k f[i][j]+=xigema f[i-1][k]
初始化f[0][0]=1,最后答案为 xigema f[n][i]
复杂度O(n*(3^m))
100pt:n,m<=100
其实之前50分做法离正解已经很接近了
再仔细思考(手玩)一下,就会发现答案与每一列棋子摆放位置无关
也就是说我们根本就没必要具体记录每一列的具体情况,只需要记录有多少列放了1个棋,有多少列放了2个棋
设f[i][j][k]表示第i行时有j列放了1个棋,有k列放了2个棋
然后转移和上面基本上没什么区别,具体请看代码
初始化f[0][0][0]=1.答案为 xigema f[n][i][j]
复杂度O(n*m*m)
Code
//Luogu P2051 [AHOI2009]中国象棋
//May,8th,2018
//状压转网格DP
#include<iostream>
#include<cstdio>
using namespace std;
long long read()
{
long long x=0,f=1; char c=getchar();
while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}
while(isdigit(c)){x=x*10+c-'0';c=getchar();}
return x*f;
}
const int N=100+10;
const int poi=9999973;
long long f[N][N][N];
int n,m;
int main()
{
n=read(),m=read(); f[0][0][0]=1;
for(int i=1;i<=n;i++)
for(int j=0;j<=m;j++)
{
int MAX_K=m-j;
for(int k=0;k<=MAX_K;k++)
{
f[i][j][k]+=f[i-1][j][k];//放0个棋子
if(j>=1) f[i][j][k]=(f[i][j][k]+f[i-1][j-1][k]*(m-k-j+1))%poi;//放1个棋子,且放在原本为0的列
if(k>=1) f[i][j][k]=(f[i][j][k]+f[i-1][j+1][k-1]*(j+1))%poi;//放1个棋子,且放在原本为1的列
if(j>=2) f[i][j][k]=(f[i][j][k]+f[i-1][j-2][k]*(((m-j-k+1)*(m-j-k+2))/2))%poi;//放2个棋子,且都放在原本为0的列
if(j>=1 and k>=1) f[i][j][k]=(f[i][j][k]+f[i-1][j][k-1]*(j*(m-j-k+1)))%poi;//放2个棋子,一个放在0,一个放在1
if(k>=2) f[i][j][k]=(f[i][j][k]+f[i-1][j+2][k-2]*(((j+1)*(j+2))/2))%poi;//放2个棋子,都放在原本为1的列
}
} long long ans=0;
for(int i=0;i<=m;i++)
{
int MAX_J=m-i;
for(int j=0;j<=MAX_J;j++)
ans=(ans+f[n][i][j])%poi;
}
printf("%lld",ans);
return 0;
}
正解(C++)
[Luogu P2051] [AHOI2009]中国象棋 (状压DP->网格DP)的更多相关文章
- 洛谷P2051 [AHOI2009] 中国象棋(状压dp)
题目简介 n*m的棋盘,对每行放炮,要求每行每列炮数<=2,求方案数%9999973 N,M<=100 题目分析 算法考虑 考虑到N,M范围较小,每一行状态只与前面的行状态有关,考虑状压D ...
- Luogu P2051 [AHOI2009]中国象棋(dp)
P2051 [AHOI2009]中国象棋 题面 题目描述 这次小可可想解决的难题和中国象棋有关,在一个 \(N\) 行 \(M\) 列的棋盘上,让你放若干个炮(可以是 \(0\) 个),使得没有一个炮 ...
- Luogu P2051[AHOI2009]中国象棋【dp】By cellur925
题目传送门 题目大意:给定一个$n*m$的棋盘,求放三个“炮”使它们不共行也不共列的方案数.($n,m$$<=100$) 这题主要是转移比较困难,因为情况比较多,所以需要冷静大胆细心地进行分情况 ...
- luogu P2051 [AHOI2009]中国象棋
统计方案,果断 dp 注意到合法方案即为每一行,每一列的棋子数不超过2 设\(f_{i,j,k}\)表示放到第\(i\)行,有\(j\)列可以放2个,有\(k\)列可以放1个的方案 然后就随便讨论一下 ...
- 洛谷 P2051 [AHOI2009]中国象棋 状态压缩思想DP
P2051 [AHOI2009]中国象棋 题意: 给定一个n*m的空棋盘,问合法放置任意多个炮有多少种情况.合法放置的意思是棋子炮不会相互打到. 思路: 这道题我们可以发现因为炮是隔一个棋子可以打出去 ...
- 洛谷 P2051 [AHOI2009]中国象棋 解题报告
P2051 [AHOI2009]中国象棋 题目描述 这次小可可想解决的难题和中国象棋有关,在一个N行M列的棋盘上,让你放若干个炮(可以是0个),使得没有一个炮可以攻击到另一个炮,请问有多少种放置方法. ...
- luogu 2051 [AHOI2009]中国象棋
luogu 2051 [AHOI2009]中国象棋 真是一道令人愉♂悦丧心并框的好题... 首先"没有一个炮可以攻击到另一个炮"有个充分条件就是没有三个炮在同一行或同一列.证明:显 ...
- [洛谷P2051] [AHOI2009]中国象棋
洛谷题目链接:[AHOI2009]中国象棋 题目描述 这次小可可想解决的难题和中国象棋有关,在一个N行M列的棋盘上,让你放若干个炮(可以是0个),使得没有一个炮可以攻击到另一个炮,请问有多少种放置方法 ...
- [P2051 [AHOI2009]中国象棋] DP
https://www.luogu.org/problemnew/show/P2051 题目描述 这次小可可想解决的难题和中国象棋有关,在一个N行M列的棋盘上,让你放若干个炮(可以是0个),使得没有一 ...
随机推荐
- Centos-修改文件访问和修改时间-touch
touch 如果文件存在,则改变文件的访问时间和修改时间,如果不存在则创建一个空文件 相关选项 -a 更改文件访问时间为当前系统时间 -m 更改文件修改时间为当前系统时间 -c 如果文 ...
- Centos-切换用户身份-su
su 切换用户身份 相关选项 - 加载相应用户下环境变量 -c 使用某个身份执行一个指令 -m 改变用户身份不改变环境变量 切换为超级用户 su - 普通用户切换为超级用户需要输入密码,超级用户 ...
- 题解 CF149D
题目链接 首先,这是一道区间dp题: 首先我们假设 \(l\) ~ \(r\) 是一段合法的区间: 考虑状态,对于一个区间 \(l\) ~ \(r\) 的方案数,我们需要知道方案数,以及 \(l ,r ...
- 使用MVC 5、Web API 2、KnockoutJS、Ninject和NUnit开发、架构和测试Web应用程序
做一名微软软件开发人员就像在国际煎饼屋订早餐一样.每道菜都有一堆煎饼,你必须从各种各样的煎饼和糖浆口味中选择.对于web应用程序,解决方案堆栈是一组软件子系统或组件,用于交付功能完整的解决方案(无论是 ...
- Docker 开启非认证的2375端口,提供外部访问 Docker
1.编辑 Docker 服务的配置文件 vi /usr/lib/systemd/system/docker.service 或者 vi /lib/systemd/system/docker.servi ...
- 多测师讲解selenium _携程选票定位练习_高级讲师肖sir
打开携程网 from selenium import webdriverfrom time import sleepfrom selenium.webdriver.common.keys import ...
- html学习(2)
标签的语义化,也就是标签的用途. html.css.javascript作用: HTML是网页内容的载体.内容就是网页制作者放在页面上想要让用户浏览的信息,可以包含文字.图片.视频等. CSS样式是表 ...
- pytest文档44-allure.dynamic动态生成用例标题
前言 pytest 结合 allure 描述用例的时候我们一般使用 @allure.title 和 @allure.description 描述测试用例的标题和详情. 在用例里面也可以动态更新标题和详 ...
- C语言编程丨循环链表实现约瑟夫环!真可谓无所不能的C!
循环链表 把链表的两头连接,使其成为了一个环状链表,通常称为循环链表. 和它名字的表意一样,只需要将表中最后一个结点的指针指向头结点,链表就能成环儿,下图所示. 需要注意的是,虽然循环链表成环 ...
- 【C语言程序设计】小游戏之俄罗斯方块(一)!适合初学者上手、练手!
俄罗斯方块的核心玩法非常简单,所以制作起来并不是很复杂,我准备先用2篇文字的篇幅详细讲解一下俄罗斯方块的制作方法. 今天咱们算是第一篇,主要讲解俄罗斯方块中如何定义方块,以及如何实现方块的移动.旋转. ...