传送门

看一眼感觉就是 $dp$,但是似乎状态太多了

考虑推推性质

首先每到一行都要把所有宝藏都走到,那么一定会走到最左边的和最右边的宝藏

注意到一旦走完所有宝藏时肯定是在最左边或者最右边的宝藏位置

并且此时要往上走,显然是选择左边或右边的最近的路上去,因为如果选择更远的路上去还不如先上去再走到更远的那个位置

所以发现,我们每一层上去只有四种选择:最左边宝藏的左右两个最近的上去,最右边宝藏的左右两个最近的上去

直接预处理一下每一层的这四个位置然后标号 $0,1,2,3$

那么就可以安心 $dp$ 了,直接设 $f[i][4]$ 表示到了第 $i$ 层并把第 $i$ 层的宝藏走完,此时准备到更上一层的位置为第 $0/1/2/3$

把一层走完直接按先到最左边或者先到最右边分类讨论一下即可

要注意我们一旦把最高的存在宝藏的一层走完即可结束,并且不用准备到更上一层,所以最后一层的转移到特殊处理一下

细节挺多的要仔细点

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
using namespace std;
typedef long long ll;
inline int read()
{
int x=,f=; char ch=getchar();
while(ch<''||ch>'') { if(ch=='-') f=-; ch=getchar(); }
while(ch>=''&&ch<='') { x=(x<<)+(x<<)+(ch^); ch=getchar(); }
return x*f;
}
const int N=4e5+;
const ll INF=1e18;
ll n,m,K,Q,b[N],L[N],R[N];
ll pre[N],nxt[N],pos[N][];
ll f[N][];
inline ll calc(ll s,ll t,int i)
{
if(s<||s>m||t<||t>m) return INF;//
if(!R[i]) return abs(s-t);//
return min( abs(s-L[i])+abs(L[i]-R[i])+abs(R[i]-t) , abs(s-R[i])+abs(L[i]-R[i])+abs(L[i]-t) );
}
int main()
{
n=read(),m=read(),K=read(),Q=read();
ll x,y; memset(L,0x3f,sizeof(L));
for(int i=;i<=K;i++)
{
x=read(),y=read();
L[x]=min(L[x],y); R[x]=max(R[x],y);
}
for(int i=;i<=Q;i++) b[i]=read();
int l=,r=; sort(b+,b+Q+); b[Q+]=m+;
for(int i=;i<=m;i++)
{
while(b[l+]<=i) l++;
while(b[r]<i) r++;
pre[i]=b[l]; nxt[i]=b[r];
}
for(int i=;i<=n;i++)
{
if(L[i]<=m) pos[i][]=pre[L[i]],pos[i][]=nxt[L[i]];
if(R[i]>=) pos[i][]=pre[R[i]],pos[i][]=nxt[R[i]];
}
memset(f,0x3f,sizeof(f));
int pre=,prre=;
for(int i=;i<;i++)
if(R[pre]) f[pre][i]=calc(,pos[pre][i],pre);
else f[pre][i]=nxt[]-,pos[pre][i]=nxt[];//
for(int i=pre+;i<=n;i++)
{
if(!R[i]) continue;
for(int j=;j<;j++)
for(int k=;k<;k++)
f[i][j]=min(f[i][j],f[pre][k]+calc(pos[pre][k],pos[i][j],i)+(i-pre));
prre=pre; pre=i;
}
ll Ans=INF;
if(!prre) { printf("%lld\n",R[pre]-); return ; }//
for(int k=;k<;k++)
Ans=min(Ans, f[prre][k]+(pre-prre)+ min(abs(pos[prre][k]-L[pre]),abs(pos[prre][k]-R[pre])) +(R[pre]-L[pre]) );//
printf("%lld\n",Ans);
return ;
}

Codeforces 1201D. Treasure Hunting的更多相关文章

  1. [Codeforces 1201D]Treasure Hunting(DP)

    [Codeforces 1201D]Treasure Hunting(DP) 题面 有一个n*m的方格,方格上有k个宝藏,一个人从(1,1)出发,可以向左或者向右走,但不能向下走.给出q个列,在这些列 ...

  2. 矩阵拿宝物--Codeforces 1201D - Treasure Hunting Codeforces Round #577 (Div. 2)

    网上题解比较少,自己比较弱研究了半天(已经过了),希望对找题解的人有帮助 题目链接:https://codeforc.es/contest/1201/problem/D 题意: 给你一个矩形,起始点在 ...

  3. Codeforces Round #577 (Div. 2) D. Treasure Hunting

    Codeforces Round #577 (Div. 2)  D. Treasure Hunting 这个一场div2 前面三题特别简单,这个D题的dp还是比较难的,不过题目告诉你了只能往上走,所以 ...

  4. [Codeforces 1214D]Treasure Island(dfs)

    [Codeforces 1214D]Treasure Island(dfs) 题面 给出一个n*m的字符矩阵,'.'表示能通过,'#'表示不能通过.每步可以往下或往右走.问至少把多少个'.'变成'#' ...

  5. codeforces 495C. Treasure 解题报告

    题目链接:http://codeforces.com/problemset/problem/495/C 题目意思:给出一串只有三种字符( ')','(' 和 '#')组成的字符串,每个位置的这个字符 ...

  6. HDU 3641 Treasure Hunting(阶乘素因子分解+二分)

    题目链接:pid=3641">传送门 题意: 求最小的 ( x! ) = 0 mod (a1^b1*a2^b2...an^bn) 分析: 首先吧a1~an进行素因子分解,然后统计下每一 ...

  7. HDU 3468 Treasure Hunting(BFS+网络流之最大流)

    题目地址:HDU 3468 这道题的关键在于能想到用网络流.然后还要想到用bfs来标记最短路中的点. 首先标记方法是,对每个集合点跑一次bfs,记录全部点到该点的最短距离.然后对于随意一对起始点来说, ...

  8. hdu 3641 Treasure Hunting 强大的二分

    /** 大意:给定一组ai,bi . m = a1^b1 *a2^b2 * a3^ b3 * a4^b4*...*ai^bi 求最小的x!%m =0 思路: 将ai 质因子分解,若是x!%m=0 那么 ...

  9. Treasure Hunting HDU - 3468

    题意: 输入一个n行m列的图 每次按字母顺序走最短路, 从一个字母走到下一个字母的过程中,只能拿走一个金子,求走完当前图中所有的字母后能拿到的金子的最大值 解析: bfs求最短路 对于一个金子如果 d ...

随机推荐

  1. zookeeper系列(四)zookeeper的使用场景

    作者:leesf    掌控之中,才会成功:掌控之外,注定失败. 出处:http://www.cnblogs.com/leesf456/p/6036548.html感谢原著公开这么好的博文供大家学习 ...

  2. 20175215 2018-2019-2 第十一周java课程学习总结

    第13章 Java网络编程 13.1 URL类 URL类是java.net包中的一个重要的类,URL的实例封装着一个统一资源定位符(Uniform Resource Locator),使用URL创建对 ...

  3. 黑马lavarel教程---12、lavarel验证码

    黑马lavarel教程---12.lavarel验证码 一.总结 一句话总结: 用插件的时候仔细看插件的版本要求 1.lavarel安装验证码插件的时候,如果(可选)需要定义自己的配置,则需要生成配置 ...

  4. sql 新建表

    CREATE TABLE `rims`.`rims_basic_dictionary_doctor_group` ( `id` INT(11) NOT NULL AUTO_INCREMENT prim ...

  5. selenium爬虫使用

    1. 网页的打开 from selenium import webdriver import time driver = webdriver.Chrome(executable_path=r" ...

  6. git远程删除分支后,本地执行git branch -a依然能看到删除分支到底该咋整?

    使用命令git branch -a可以查看所有本地分支和远程分支(git branch -r 可以只查看远程分支) 如果发现很多在远程仓库已经删除的分支在本地依然可以看到到底该怎么办呢?(反正强迫症受 ...

  7. Canvas学习:封装Canvas绘制基本图形API

    Canvas学习:封装Canvas绘制基本图形API Canvas Canvas学习   从前面的文章中我们了解到,通过Canvas中的CanvasRenderingContext2D对象中的属性和方 ...

  8. for...in 与 for...of

    在js中, 对于Object,一般for...in 来进行迭代,不能使用for...of     // let obj = {a:1,b:2} for(let i of obj){console.lo ...

  9. GCC 9.2 2019年8月12日 出炉啦

    GNU 2019-08-12 发布了 GCC 9.2https://gcc.gnu.org/onlinedocs/9.2.0/ 有详细的说明 MinGW 上可用的 GCC 9.2 版本下载地址 [ m ...

  10. react中路由跳转push与replace的区别

    路由跳转,replace / push 区别 push: a-b-c 可以回到上一级 例: this.props.history.push('路由地址') replace: a-b-c 回不到上一级 ...