LG_2051_[AHOI2009]中国象棋
题目描述
这次小可可想解决的难题和中国象棋有关,在一个N行M列的棋盘上,让你放若干个炮(可以是0个),使得没有一个炮可以攻击到另一个炮,请问有多少种放置方法。大家肯定很清楚,在中国象棋中炮的行走方式是:一个炮攻击到另一个炮,当且仅当它们在同一行或同一列中,且它们之间恰好 有一个棋子。你也来和小可可一起锻炼一下思维吧!
输入输出格式
输入格式
一行包含两个整数N,M,之间由一个空格隔开。
输出格式
总共的方案数,由于该值可能很大,只需给出方案数模9999973的结果。
样例
INPUT
1 3
OUTPUT
7
HINT
样例说明
除了3个格子里都塞满了炮以外,其它方案都是可行的,所以一共有222-1=7种方案。
数据范围
100%的数据中N和M均不超过100
50%的数据中N和M至少有一个数不超过8
30%的数据中N和M均不超过6
SOLUTION
dp
本题我一开始想往状压上靠,对于每个状态,我们记一个类似于三进制的数来维护状态,但是由于数据范围十分的迷,100说大也不大,有的题\(10^7\)的都有(当然不是状压题),说大也大,100位的数怎么存怎么转移都是不好处理的问题。于是放弃思考直奔题解。
题解提示了一个重要的问题:和Brick game那题一样,本题对两行之间的状态转移并没有特殊要求,换句话说其实我们并不关心走到最后到底是哪些列没有炮,哪些列只有一个,哪些列只有两个,我们只关心到底有多少列没有炮,有多少列只有一个炮,有多少列有两个炮。而由于题目给出的限制,同一行最多只能新增两个炮,所以可以实现\(O(1)\)的转移。
所以我们可以考虑设dp数组为\(dp[i][j][k]\)表示第\(i\)行,前\(i\)行有\(j\)列含有一个炮,有\(k\)列含有2个炮。
所以转移可以是这样:
- 本行放两个,全部放在原来为空不同两列;
- 本行放两个,一个放在原有一个的某列,一个放在为空的某列;
- 本行放两个,全部放在原有一个的不同两列;
- 本行放一个,放在空列;
- 本行放一个,放在原有一个的某列;
- 本行不放炮。
(我代码里也是按此顺序转移的,权当作是注释看吧)
由此题又可以发现,其实对于很多dp题,它们的优化往往会从优化状态转移入手,对于有多个状态转移方式的dp,应该考虑清楚这些具体状态是否必要,可否简化为一种抽象的状态,这种思路在洛谷2018年11月月赛T3咕咕咕的正解中也有体现,是一种比较好的思路。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
using namespace std;
typedef long long LL;
const int N=110;
const int P=9999973;
int n,m;
LL dp[N][N][N];
inline LL C2(LL num) {LL ans=(num)*(num-1)/2;return ans;}
int main(){
int i,j;
scanf("%d%d",&n,&m);
memset(dp,0,sizeof(dp));
dp[0][0][0]=1;
for (i=0;i<n;++i){
for (j=0;j<=m;++j){
for (int k=0;(j+k)<=m;++k){
if (m-j-k>1) dp[i+1][j+2][k]=(dp[i+1][j+2][k]+dp[i][j][k]*C2(m-j-k))%P;
if ((m-j-k>0)&&(j>0)) dp[i+1][j][k+1]=(dp[i+1][j][k+1]+dp[i][j][k]*(m-j-k)*(j)%P)%P;
if (j>1) dp[i+1][j-2][k+2]=(dp[i+1][j-2][k+2]+dp[i][j][k]*C2(j)%P)%P;
if (m-j-k>0) dp[i+1][j+1][k]=(dp[i+1][j+1][k]+dp[i][j][k]*(m-j-k)%P)%P;
if (j>0) dp[i+1][j-1][k+1]=(dp[i+1][j-1][k+1]+dp[i][j][k]*(j)%P)%P;
dp[i+1][j][k]=(dp[i+1][j][k]+dp[i][j][k])%P;
}
}
}
LL ans=0;
for (i=0;i<=m;++i)
for (j=0;(i+j)<=m;++j)
ans=(ans+dp[n][i][j])%P;
printf("%lld\n",ans);
return 0;
}
LG_2051_[AHOI2009]中国象棋的更多相关文章
- 洛谷 P2051 [AHOI2009]中国象棋 解题报告
P2051 [AHOI2009]中国象棋 题目描述 这次小可可想解决的难题和中国象棋有关,在一个N行M列的棋盘上,让你放若干个炮(可以是0个),使得没有一个炮可以攻击到另一个炮,请问有多少种放置方法. ...
- luogu 2051 [AHOI2009]中国象棋
luogu 2051 [AHOI2009]中国象棋 真是一道令人愉♂悦丧心并框的好题... 首先"没有一个炮可以攻击到另一个炮"有个充分条件就是没有三个炮在同一行或同一列.证明:显 ...
- [洛谷P2051] [AHOI2009]中国象棋
洛谷题目链接:[AHOI2009]中国象棋 题目描述 这次小可可想解决的难题和中国象棋有关,在一个N行M列的棋盘上,让你放若干个炮(可以是0个),使得没有一个炮可以攻击到另一个炮,请问有多少种放置方法 ...
- 洛谷 P2051 [AHOI2009]中国象棋 状态压缩思想DP
P2051 [AHOI2009]中国象棋 题意: 给定一个n*m的空棋盘,问合法放置任意多个炮有多少种情况.合法放置的意思是棋子炮不会相互打到. 思路: 这道题我们可以发现因为炮是隔一个棋子可以打出去 ...
- Luogu P2051 [AHOI2009]中国象棋(dp)
P2051 [AHOI2009]中国象棋 题面 题目描述 这次小可可想解决的难题和中国象棋有关,在一个 \(N\) 行 \(M\) 列的棋盘上,让你放若干个炮(可以是 \(0\) 个),使得没有一个炮 ...
- [Luogu P2051] [AHOI2009]中国象棋 (状压DP->网格DP)
题面 传送门:https://www.luogu.org/problemnew/show/P2051 Solution 看到这题,我们不妨先看一下数据范围 30pt:n,m<=6 显然搜索,直接 ...
- P2051 [AHOI2009]中国象棋
题目描述 这次小可可想解决的难题和中国象棋有关,在一个N行M列的棋盘上,让你放若干个炮(可以是0个),使得没有一个炮可以攻击到另一个炮,请问有多少种放置方法.大家肯定很清楚,在中国象棋中炮的行走方式是 ...
- [AHOI2009]中国象棋
题目描述 这次小可可想解决的难题和中国象棋有关,在一个N行M列的棋盘上,让你放若干个炮(可以是0个),使得没有一个炮可以攻击到另一个炮,请问有多少种放置方法.大家肯定很清楚,在中国象棋中炮的行走方式是 ...
- [P2051 [AHOI2009]中国象棋] DP
https://www.luogu.org/problemnew/show/P2051 题目描述 这次小可可想解决的难题和中国象棋有关,在一个N行M列的棋盘上,让你放若干个炮(可以是0个),使得没有一 ...
随机推荐
- PAT Advanced 1033 To Fill or Not to Fill (25) [贪⼼算法]
题目 With highways available, driving a car from Hangzhou to any other city is easy. But since the tan ...
- python语法基础-并发编程-进程-进程池以及回调函数
############### 进程池 ############## """ 进程池的概念 为什么会有进程池? 1,因为每次开启一个进程,都需要创建一个内存空间 ...
- vue wangeditor3封装
<script src="wangEditor/3.1.1/wangEditor.min.js"></script> Vue.component('my ...
- docker 一些简略环境搭建及部分链接
1.center 7 搭建 docker https://www.cnblogs.com/yufeng218/p/8370670.html 2.docker 命令 https://www.cnblo ...
- Python这五个坑,80%你不知道(对的,五个你知道1个就达到一般水平了)
1 含单个元素的元组 Python中有些函数的参数类型为元组,其内有1个元素,这样创建是错误的: c = (5) # NO! 它实际创建一个整型元素5,必须要在元素后加一个逗号: ! c = (5,) ...
- 吴裕雄--天生自然 pythonTensorFlow自然语言处理:交叉熵损失函数
import tensorflow as tf # 1. sparse_softmax_cross_entropy_with_logits样例. # 假设词汇表的大小为3, 语料包含两个单词" ...
- 利用CSS制作背景变色的横向导航栏
1.表单 页面如下: <html> <head> <title>注册表单页面</title> </head> <body> &l ...
- 吴裕雄--天生自然python学习笔记:python 用 Open CV抓取摄像头视频图像
Open CV 除了可以读取.显示静态图片外 , 还可 以加载及播放动态影片, 以 及 读取内置或外接摄像头的图像信息 . 很多笔记本电脑都具有摄像头 , OpenCV 可通过 VideoC aptu ...
- Leetcode 5039. 移动石子直到连续
第134次周赛 5039. 移动石子直到连续 5039. 移动石子直到连续 三枚石子放置在数轴上,位置分别为 a,b,c. 每一回合,我们假设这三枚石子当前分别位于位置 x, y, z 且 x < ...
- .net core ioc
-------------------------------------- 2. ---------------------------- -----------aop