[BZOJ4859][BJOI2017]机动训练(DP)
4859: [BeiJing2017]机动训练
Time Limit: 20 Sec Memory Limit: 256 MB
Submit: 105 Solved: 63
[Submit][Status][Discuss]Description
AM 4:45又是晴朗的好天气。AM 5:00不要嘛,再睡一会AM 5:05呜……欺负人——————————————————睡眼朦胧的菜酱(?)已经被二爷拉起来晨跑了。而这个时间你在做什么呢?咳咳,言归正传,最近菜酱的训练遇到了点小麻烦。凌晨绕格瑞赛亚岛跑一圈是基本,在那之后,菜酱还要接受严格的机动训练所谓机动训练,就是在紧急情况(?)下,高速且隐蔽地从位置 X 移动到位置 Y 的训练一般来说, X 和 Y 是根据二爷的心情随机决定的但是由于菜酱已经熟悉了地形,每次总是能找到不太费劲的路径,二爷决定增大难度所谓增大难度,其实就是指定整条路径,这样菜酱就没办法抄近道了当然,由于是为了实战而进行的训练,二爷也不会随便乱指定路径,至少不会故意绕路然后发生的问题就是,如何才能“随机”一整条路径出来二爷统计了全岛所有的合法路径,打算每次在这个表格里随机抽一条出来但是很快二爷发现,许多路径所经过的地形是完全相同的,这类路径的训练会更加有用于是二爷修改了随机策略,地形较为常见的路径权重会变得更大。一次偶然的机会,菜酱看到了二爷的随机策略,并发动技能"过目不忘(?)"记了下来现在你要帮菜酱分析数据。为什么是你?当然是因为否则就会被菜酱爆头(并不)整个岛可以看作一片 n*m 的区域,每个格子有自己的地形。一条路径由一系列八连通的格子组成,两个格子八连通当且仅当这两个格子拥有公共的顶点。定义一条“机动路径”如下:1、它是一条不自交的路径,即路径上任意两个格子都不是同一个2、它的起点和终点处于不同位置,换言之这条路径至少包含 2 个格子3、从起点开始,任何一步只能向不远离终点的方向移动,这里不远离指的是 x 和 y 两个方向都不远离举例说明(字符画需要用等宽字体查看):.....y ...... .---.-++... ---... .-x-.-x+... -x+..y .-+-.---... ---... ..y..图中加号和减号标明了与 x 八连通的所有格子,其中加号是“不远离 y”的方向因此可以看出,如下路径是机动路径:++++++y ......+y .......y+...... .....++. ......+.+...... ..++++.. ...+++..x...... x++..... x+++....而如下路径不是机动路径:\../---y .......y .x.|--..... ....../. /..|....... x..../.. \..x....... .\--/... .y.需要注意的是,某些不合法的路径甚至比机动路径还要短,这是因为机动路径不是按照长度来定义的。接下来定义一条机动路径的地形,岛上的地形由一个矩阵给出,如.**.*..**..*.**.那么,一条机动路径的地形序列就是它所经过的地形排成一列,如x-\....\...|...y的地形序列就是".****."(不包含引号)每条机动路径的权重就是与之拥有相同地形序列的机动路径数量之和,例如与这条路径拥有相同地形序列的路径有./-y y... ...x x-\. ./-x x... ...y y-\./... |... ...| ...\ /... |... ...| ...\|... \... .../ ...| |... \... .../ ...|x... .\-x y-/. ...y y... .\-y x-/. ...x共 8 条,注意回文时正反算两条,以及自己也算一条。所以这条机动路径的权重是 8,同时所有这 8 条机动路径的权重都是 8。现在你需要统计所有的机动路径权重之和。如果对这种统计方式没有直观的感受,可以查看样例说明。Input
第一行两个整数 n, m,表示岛的大小。接下来 n 行,每行 m 个字符,表示岛的地形。字符集随数据规模给出。对于 100%的数据, 1 ≤ n, m ≤ 30,字符集由大小写字母,数字和"."、 "*"构成Output
仅一个数,表示所有机动路径的权重之和。由于这个数可能很大,你只需要输出它对 1000000009 取模的结果。Sample Input
2 2
.*
*.Sample Output
72
【样例解释 1】
用中括号括起来的一些数对表示一条机动路径,坐标先行后列
地形序列".*": [(1, 1), (1, 2)], [(1, 1), (2, 1)], [(2, 2), (2, 1)], [(2, 2),
(1, 2)],共 4 条,每条权重为 4,计 16
地形序列"*.": [(1, 2), (1, 1)], [(2, 1), (1, 1)], [(2, 1), (2, 2)], [(1, 2),
(2, 2)],共 4 条,每条权重为 4,计 16
地形序列"..": [(1, 1), (2, 2)], [(2, 2), (1, 1)],共 2 条,每条权重为 2,计 4
地形序列"**": [(1, 2), (2, 1)], [(2, 1), (1, 2)],共 2 条,每条权重为 2,计 4
地形序列".*.": [(1, 1), (1, 2), (2, 2)], [(1, 1), (2, 1), (2, 2)], [(2, 2),
(2, 1), (1, 1)], [(2, 2), (1, 2), (1, 1)],共 4 条,每条权重为 4,计 16
地形序列"*.*": [(1, 2), (1, 1), (2, 1)], [(2, 1), (1, 1), (1, 2)], [(1, 2),
(2, 2), (2, 1)], [(2, 1), (2, 2), (1, 2)],共 4 条,每条权重为 4,计 16
共计 16+16+4+4+16+16=72HINT
Source
BZOJ体面惨不忍睹,还是上LOJ看吧。
数据范围就是跪着求我们DP,而且本体重点不是时空复杂度而是码长,技巧越好编程复杂度越小。
1.平方处理:类似管道取珠,A的位置和B的位置一起作为状态转移,记忆化。
2.容斥:减小码长的利器,将每个方向的值求出,然后将s和t不在同一行/列的方案数减去在同一行/列的方案数。
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
#define rep(i,l,r) for (int i=l; i<=r; i++)
using namespace std; const int N=,mod=1e9+; struct pii { int x,y; pii(int x=,int y=):x(x),y(y) {} }; int n,m,f[N][N][N][N],g[][][][],ans=;
char map[N][N];
vector<pii> dxy1,dxy2; void add(int &x,int v) { x+=v; if(x>=mod)x-=mod; } int Dp(int x1,int y1,int x2,int y2) {
if(x1<||x1>n||y1<||y1>m||x2<||x2>n||y2<||y2>m||map[x1][y1]!=map[x2][y2])return ;
if(~f[x1][y1][x2][y2])return f[x1][y1][x2][y2];
f[x1][y1][x2][y2]=;
for (vector<pii>::iterator d1=dxy1.begin(); d1!=dxy1.end(); d1++)
for (vector<pii>::iterator d2=dxy2.begin(); d2!=dxy2.end(); d2++)
add(f[x1][y1][x2][y2],Dp(x1+d1->x,y1+d1->y,x2+d2->x,y2+d2->y));
return f[x1][y1][x2][y2];
} int Solve(int dx1,int dy1,int dx2,int dy2) {
if(~g[dx1+][dy1+][dx2+][dy2+])return g[dx1+][dy1+][dx2+][dy2+];
dxy1.clear(),dxy2.clear();
rep(i,-,){
if(i&&i!=dx1)continue;
rep(j,-,)
if(!(!i&&!j) && !(j&&j!=dy1)) dxy1.push_back(pii(i,j));
}
rep(i,-,){
if(i&&i!=dx2)continue;
for(int j=-; j<=; j++)
if (!(!i&&!j) && !(j&&j!=dy2)) dxy2.push_back(pii(i,j));
}
memset(f,-,sizeof(f)); int sum=;
rep(x1,,n) rep(y1,,m) rep(x2,,n) rep(y2,,m) add(sum,Dp(x1,y1,x2,y2));
g[dx1+][dy1+][dx2+][dy2+]=g[dx2+][dy2+][dx1+][dy1+]=sum;
g[-dx1+][-dy1+][-dx2+][-dy2+]=g[-dx2+][-dy2+][-dx1+][-dy1+]=sum;
return sum;
} int Solve(int x,int y) {
int sum=;
add(sum,Solve(-,-,x,y)); add(sum,Solve(-,,x,y)); add(sum,Solve(,-,x,y)); add(sum,Solve(,,x,y));
add(sum,mod-Solve(-,,x,y)); add(sum,mod-Solve(,,x,y)); add(sum,mod-Solve(,-,x,y)); add(sum,mod-Solve(,,x,y));
return sum;
} int main(){
scanf("%d%d",&n,&m);
rep(i,,n) scanf("%s",map[i]+);
memset(g,-,sizeof(g));
add(ans,Solve(-,-)); add(ans,Solve(-,)); add(ans,Solve(,-)); add(ans,Solve(,));
add(ans,mod-Solve(-,)); add(ans,mod-Solve(,)); add(ans,mod-Solve(,-)); add(ans,mod-Solve(,));
printf("%d\n",ans);
return ;
}
[BZOJ4859][BJOI2017]机动训练(DP)的更多相关文章
- P3713 [BJOI2017]机动训练
这个题简直神仙,求相同路径的平方就等于两个人走相同路径的方案数.然后...暴力搜索+记忆化就行了,比较玄学. 题干: 题目描述 整个岛可以看作一片 n*m 的区域,每个格子有自己的地形. 一条路径由一 ...
- BJOI2017 机动训练
落谷.Loj. Description 定义机动路径为: 没有自环 路径至少包含两个格子 从起点开始每一步都向不远离终点的方向移动 相同地形序列指路径上顺序经过的地形序列. 定义机动路径的权值为相同地 ...
- 【LOJ】#2178. 「BJOI2017」机动训练
题解 遇见平方和就转有序对呗 dp类似从很多点出发每次走一步的转移方式 然后我too naive的,枚举路径长度来决定更新次数,愉快TLE 改成记搜就过了 代码 #include <bits/s ...
- bzoj 4859 [BeiJing2017]机动训练
题面 https://www.lydsy.com/JudgeOnline/problem.php?id=4859 题解 和管道取珠类似 首先把平方转化成两条路径经过的图案相同的方案数 对于一条路径 方 ...
- AHOI2018训练日程(3.10~4.12)
(总计:共90题) 3.10~3.16:17题 3.17~3.23:6题 3.24~3.30:17题 3.31~4.6:21题 4.7~4.12:29题 ZJOI&&FJOI(6题) ...
- 一个小 Trick
平方变两次 一个状态 \(S\) 有一个贡献,所有状态 \(S\) 组成集合 \(U\) . 然后我们要统计下面这个东西 \[ans=\sum_{S\in U}f^2(S) \] 然后我们就可以看作是 ...
- NOI Online #2 提高组 游记
没 NOI Online 1 挂的惨就来写游记吧,不知道为啥 NOI Online 1 民间数据测得 60 分的 T1 最后爆零了... 昏昏沉沉的醒来,吃了早饭,等到 \(8:30\) 进入比赛网页 ...
- HDU_1024.MaxSumPlusPlus(基础DP + 滚动数组优化讲解)
这道题打破了我常规的做题思路,因为这是我刚开始训练DP,感觉这道题目好晕眼呀,emm其实就是感觉自己是真的菜...... 为什么说打破了我的做题思路呢,因为我平时看题解都是在已经AC或者完全不懂的情况 ...
- BJOI做题记录
BJOI做题记录 终于想起还要做一下历年省选题了2333 然而咕了的还是比做了的多2333 LOJ #2178. 「BJOI2017」机动训练 咕了. LOJ #2179. 「BJOI2017」树的难 ...
随机推荐
- 【Luogu】P3927 SAC E#1 - 一道中档题 Factorial
[题目]洛谷10月月赛R1 提高组 [题意]求n!在k进制下末尾0的个数,n<=1e18,k<=1e16. [题解]考虑10进制末尾0要考虑2和5,推广到k进制则将k分解质因数. 每个质因 ...
- Spring boot 集成Dubbox(山东数漫江湖)
前言 因为工作原因,需要在项目中集成dubbo,所以去查询dubbo相关文档,发现dubbo目前已经不更新了,所以把目光投向了dubbox,dubbox是当当网基于dubbo二次开发的一个项目,dub ...
- NodeJS中Buffer模块详解
一,开篇分析 所谓缓冲区Buffer,就是 "临时存贮区" 的意思,是暂时存放输入输出数据的一段内存. JS语言自身只有字符串数据类型,没有二进制数据类型,因此NodeJS提供了一 ...
- windows下 nginx安装 使用
介绍 Nginx (engine x) 是一个高性能的HTTP和反向代理服务器. 反向代理(Reverse Proxy)方式是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络 ...
- 我的spring boot,杨帆、起航!
快速新建一个spring boot工程可以去http://start.spring.io/这个网址,配置完后会自动下载一个工程的压缩包,解压后导入相关ide工具即可使用. 工程中会自带一个class启 ...
- 集合框架源码学习之HashMap(JDK1.8)
目录: 0-1. 简介 0-2. 内部结构分析 0-2-1. JDK18之前 0-2-2. JDK18之后 0-3. LinkedList源码分析 0-3-1. 构造方法 0-3-2. put方法 0 ...
- 某labs上传writeup-上传漏洞总结
github:https://github.com/d0ef/upload-labs 第一题:通过JS判断的直接抓包改了就ok. 第二题:只要Content-Type信息为图片的就可以 第三题:通过上 ...
- k8s取节点内docker中的日志
Kubernetes(k8s)是Google开源的容器集群管理系统(谷歌内部:Borg).在Docker技术的基础上,为容器化的应用提供部署运行.资源调度.服务发现和动态伸缩等一系列完整功能,提高了大 ...
- Linux NAPI/非NAPI
本文主要介绍二层收包流程,包括NAPI与非NAPI方式: NAPI:数据包到来,第一个数据包产生硬件中断,中断处理程序将设备的napi_struct结构挂在当前cpu的待收包设备链表softnet_d ...
- Linux线程同步
1. 线程同步: 当多个控制线程共享相同的内存时,需要确保每个线程看到一致的数据视图.当某个线程可以修改变量,而其他线程也可以读取或者修改这个变量的时候,就需要对这些线程进行同步,以确保他们在访问变量 ...