[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个),使得没有一 ...
随机推荐
- python_用户登录验证
登录验证,三次机会,如何做? 1. 一个用户列表记录合法密码和用户名,一个小黑屋列表记录输错3次的用户, 一个中间列表记录所有用户输入,统计某个用户是否输错3次 2. 通过 in 判断一个元素是否在一 ...
- CTFweb方向小知识点
1)转义字符 \x35\x35\x2c\x35\x36\x2c\x35\x34\x2c\x37\x39 这玩意叫转义字符,在C.C++里直接用cout << "\x35\x2c\ ...
- Arduino各开发板
参考来源:https://www.arduino.cn/thread-42417-1-1.html 查了好久,发现除了奈何等等几位大神总结过arduino各板子之间的性能.差异,没有很新的分析文章,在 ...
- Vue.js 学习笔记之四:Vue 组件基础
到目前为止,这个系列的笔记所展示的都是一些极为简单的单页面 Web 应用程序,并且页面上通常只有几个简单的交互元素.但在实际生产环境中,Web 应用程序的用户界面往往是由多个复杂的页面共同组成的.这时 ...
- 初探电波钟(A Brief Introduction Of Radio Controlled Clock AND Its Appliciations)
文档标识符:Radio_Controlled_Clock_T-D-P11 作者:DLHC 最后修改日期:2020.10.12 本文链接:https://www.cnblogs.com/DLHC-TEC ...
- firewalld和iptables区别
在RHEL7里有几种防火墙共存:firewalld.iptables.ebtables,默认是使用firewalld来管理netfilter子系统,不过底层调用的命令仍然是iptables等. fir ...
- java读取中文乱码解决方法
Java读取文本文件(例如csv文件.txt文件等),遇到中文就变成乱码.读取代码如下: List<String> lines=new ArrayList<String>(); ...
- QJsonObject 遍历
遍历QjsonObject方式 方式一 QJsonObject::const_iterator it = l_obj.constBegin(); QJsonObject::const_iterator ...
- Dijkstra算法 python实现
1.Dijkstra算法的基本实现 \(O(n^2)\) 简介: Dijkstra算法是从一个顶点到其余各顶点的最短路径算法,解决的是有权图中最短路径问题.迪杰斯特拉算法主要特点是从起始点开始,采用贪 ...
- 大白话聊OSI七层模型和TCP/IP四层模型
前言 今天和大家聊的是一个比较基础的问题,OSI七层模型和TCP/IP四层模型. 小伙伴们可能有疑问,这个东西还用写文章吗,太基础了吧,网上文章多的是,随便一搜索就能找到. 确实是这样,网上资料确实很 ...