[Codeforces 1201D]Treasure Hunting(DP)
[Codeforces 1201D]Treasure Hunting(DP)
题面
有一个n*m的方格,方格上有k个宝藏,一个人从(1,1)出发,可以向左或者向右走,但不能向下走。给出q个列,在这些列上可以向上走,其他列不能向上走。可以重复经过同一个点。求从(1,1)出发,经过所有宝藏的最短路径长度
\(n,m,k,q \leq 2 \times 10^5\)
分析
贪心考虑,我们应该按照行一层一层的走。每一行应该从最左的宝藏走到最右的宝藏,或者从最右的宝藏走到最左的宝藏,然后找最近的一个可以向上走的列,走到另一行。
设\(dp[i][0/1]\)表示当前在第i行最左边的宝藏,或者最右边的宝藏,已经走完该行所有宝藏的最短距离
那么只要记录上一个有宝藏的行pre,分类讨论一下四种转移
\(dp[i][0]\)需要先走到第i行的最右端,再从第i行的最右端走到最左端
\(dp[i][1]\)需要先走到第i行的最右端,再从第i行的最右端走到最左端
另一个问题是如何计算(x1,y1)到(x2,y2)的距离。我们预处理在第i列左边最近的可以向上走的列lb[i],和最右边最近的列rb[i],那么我们走的列一定是lb[y1],lb[y2],rb[y1],rb[y2]四列中的一列。
如下图,假设y1<y2,走lb[y1]左侧的一列显然不如lb[y1]优,走rb[y2]右侧的一列显然不如rb[y2]优,而走rb[y1],lb[y2]中间的列和直接走rb[y1],lb[y2]一样

把经过这四列向上的距离统计出来就可以了
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define maxn 200000
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
int n,m,k,q;
vector<int>a[maxn+5];
int lb[maxn+5],rb[maxn+5];
int col[maxn+5];
ll dp[maxn+5][2];//走到最左侧/最右侧结束
ll calc(int y1,int y2,int line){//从y1到第line列,走上去,再到y2
return (ll)abs(y1-line)+abs(y2-line);
}
ll dist(int x1,int y1,int x2,int y2){
ll distx=abs(x1-x2);
ll disty=min(min(calc(y1,y2,lb[y1]),calc(y1,y2,lb[y2])),min(calc(y1,y2,rb[y1]),calc(y1,y2,rb[y2])));
return distx+disty;
}
int main(){
int x,y;
scanf("%d %d %d %d",&n,&m,&k,&q);
for(int i=1;i<=k;i++){
scanf("%d %d",&x,&y);
a[x].push_back(y);
}
for(int i=1;i<=q;i++){
scanf("%d",&col[i]);
}
sort(col+1,col+1+q);
col[0]=-INF;
col[q+1]=INF;
for(int i=1;i<=m;i++){
lb[i]=col[lower_bound(col+1,col+1+q,i)-col-1];
rb[i]=col[lower_bound(col+1,col+1+q,i)-col];
}
sort(a[1].begin(),a[1].end());
if(!a[1].empty()){
dp[1][0]=dp[1][1]=a[1].back()-1;
a[1][0]=a[1].back();
//第一行必须从最后一个关键点往上走,否则就走不完所有关键点
}else{
a[1].push_back(1);
dp[1][0]=dp[1][1]=0;
}
int last=1;
for(int i=2;i<=n;i++){
if(!a[i].empty()){
sort(a[i].begin(),a[i].end());
ll l_to_l=dp[last][0]+dist(last,a[last].front(),i,a[i].front());//从pre行最左侧走到i行最左侧
ll r_to_l=dp[last][1]+dist(last,a[last].back(),i,a[i].front()); //从pre行最右侧走到i行最左侧
ll l_to_r=dp[last][0]+dist(last,a[last].front(),i,a[i].back());//从pre行最左侧走到i行最右侧
ll r_to_r=dp[last][1]+dist(last,a[last].back(),i,a[i].back());//从pre行最右侧走到i行最右侧
ll now=a[i].back()-a[i].front();//走完当前行的代价
dp[i][0]=min(l_to_r,r_to_r)+now;//先走到最右侧,最后到最左侧
dp[i][1]=min(l_to_l,r_to_l)+now;//先走到最左侧,最后到最右侧
last=i;
}
}
printf("%I64d\n",min(dp[last][0],dp[last][1]));
}
[Codeforces 1201D]Treasure Hunting(DP)的更多相关文章
- Codeforces 1201D. Treasure Hunting
传送门 看一眼感觉就是 $dp$,但是似乎状态太多了 考虑推推性质 首先每到一行都要把所有宝藏都走到,那么一定会走到最左边的和最右边的宝藏 注意到一旦走完所有宝藏时肯定是在最左边或者最右边的宝藏位置 ...
- 矩阵拿宝物--Codeforces 1201D - Treasure Hunting Codeforces Round #577 (Div. 2)
网上题解比较少,自己比较弱研究了半天(已经过了),希望对找题解的人有帮助 题目链接:https://codeforc.es/contest/1201/problem/D 题意: 给你一个矩形,起始点在 ...
- Codeforces Round #577 (Div. 2) D. Treasure Hunting
Codeforces Round #577 (Div. 2) D. Treasure Hunting 这个一场div2 前面三题特别简单,这个D题的dp还是比较难的,不过题目告诉你了只能往上走,所以 ...
- [Codeforces 1214D]Treasure Island(dfs)
[Codeforces 1214D]Treasure Island(dfs) 题面 给出一个n*m的字符矩阵,'.'表示能通过,'#'表示不能通过.每步可以往下或往右走.问至少把多少个'.'变成'#' ...
- codeforces 505C C. Mr. Kitayuta, the Treasure Hunter(dp)
题目链接: C. Mr. Kitayuta, the Treasure Hunter time limit per test 1 second memory limit per test 256 me ...
- Codeforces Round #286 Div.1 A Mr. Kitayuta, the Treasure Hunter --DP
题意:0~30000有30001个地方,每个地方有一个或多个金币,第一步走到了d,步长为d,以后走的步长可以是上次步长+1,-1或不变,走到某个地方可以收集那个地方的财富,现在问走出去(>300 ...
- codeforces 505C Mr. Kitayuta, the Treasure Hunter(dp)
题意:有30001个岛,在一条线上,从左到右编号一次为0到30000.某些岛屿上有些宝石.初始的时候有个人在岛屿0,他将跳到岛屿d,他跳跃的距离为d.如果当前他跳跃的距离为L,他下一次跳跃的距离只能为 ...
- Codeforces.739E.Gosha is hunting(DP 带权二分)
题目链接 \(Description\) 有\(n\)只精灵,两种精灵球(高级和低级),每种球能捕捉到第\(i\)只精灵的概率已知.求用\(A\)个低级球和\(B\)个高级球能捕捉到精灵数的最大期望. ...
- codeforces Hill Number 数位dp
http://www.codeforces.com/gym/100827/attachments Hill Number Time Limits: 5000 MS Memory Limits: ...
随机推荐
- OCP
desc dba_objects; select * from dba_objects where rownum = 6; select owner, object_id from dba_objec ...
- CentOS搭建NodeJs服务器—Mongodb安装
1.下载Mongodb 直接下载(下载很慢) cd /mongdb wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-amazon- ...
- 【bzoj1176】[Balkan2007]Mokia
题目描述: 维护一个W*W的矩阵,初始值均为S.每次操作可以增加某格子的权值,或询问某子矩阵的总权值.修改操作数M<=160000,询问数Q<=10000,W<=2000000. 输 ...
- Java网络编程与NIO详解11:Tomcat中的Connector源码分析(NIO)
本文转载 https://www.javadoop.com 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.c ...
- el-date-picker用法
需求:1.默认时间是当天开始到此刻的时间 2.快捷键为今天.昨天.最近一周.最近30天.最近90天 3.不可以清空,必选项
- Glide 图片框架
学习参考:https://blog.csdn.net/guolin_blog/article/details/53759439 一 基础使用 Picasso比Glide更加简洁和轻量,Glide比Pi ...
- 007-Spring Boot-@Enable*注解的工作原理-EnableConfigurationProperties、ImportSelector、ImportBeanDefinitionRegistrar
一.@Enable* 启用某个特性的注解 1.EnableConfigurationProperties 回顾属性装配 application.properties中添加 tomcat.host=19 ...
- 初窥AST
一个简单的AST示例: AST结构: 里面有program.name.loc.type.comments.tokens 先看program: 重点关注program里面的body这个数组: JS引擎中 ...
- if else 更优雅的写法(转)
https://www.cnblogs.com/y896926473/articles/9675819.html
- 阶段1 语言基础+高级_1-3-Java语言高级_04-集合_08 Map集合_10_练习_计算一个字符串中每个字符出现的次数