传送门

Luogu

解题思路

第一步预处理每个点后面的最近点和次近点,然后就是模拟题意。

但是如果就这么搞是 \(O(N^2)\) 的,不过可以过70分,考场上也已经比较可观了。

考虑优化。

预处理最近点和次近点的过程可以用 set 优化到 \(O(n \log n)\),也可以用双向链表优化到 \(O(n)\)。

这里介绍双向链表的做法。

把所有点装入一个结构体中,按高度降序排序。

那么我们每次取出一个点,可能更新它的最近点和次近点的点只会是它的前驱、前驱的前驱、后继、后继的后继,更新四次就好了。

然后用倍增优化一下开车的过程,具体实现看代码,因为这个就是对暴力的优化,没什么技术含量,不过细节有点多就是了。

细节注意事项

  • 细节挺多的啊。。。

参考代码

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cctype>
#include <cmath>
#include <ctime>
#define rg register
using namespace std;
template < class T > inline void read(T& s) {
s = 0; int f = 0; char c = getchar();
while (!isdigit(c)) f |= c == '-', c = getchar();
while (isdigit(c)) s = s * 10 + c - 48, c = getchar();
s = f ? -s : s;
} typedef long long LL;
const int _ = 100002;
const double eps = 1e-7; int n, r1[_], r2[_], pos[_];
struct node { int h, id, pre, nxt; } t[_];
inline bool cmp(const node& x, const node& y) { return x.h < y.h; } int r3[20][_], dis1[20][_], dis2[20][_]; inline void upt(int i, int p, int j) {
if (j < 1 || j > n) return ;
LL d = abs(t[p].h - t[j].h);
LL d1 = abs(t[pos[i]].h - t[pos[r1[i]]].h);
LL d2 = abs(t[pos[i]].h - t[pos[r2[i]]].h);
if (!r1[i] || d1 > d || (d1 == d && t[j].h < t[pos[r1[i]]].h))
r2[i] = r1[i], r1[i] = t[j].id;
else if (!r2[i] || d2 > d || (d2 == d && t[j].h < t[pos[r2[i]]].h))
r2[i] = t[j].id;
} int main() {
#ifndef ONLINE_JUDGE
freopen("cpp.in", "r", stdin);
freopen("cpp.out", "w", stdout);
#endif
read(n);
for (rg int i = 1; i <= n; ++i) read(t[i].h), t[i].id = i;
sort(t + 1, t + n + 1, cmp);
for (rg int i = 1; i <= n; ++i) {
pos[t[i].id] = i;
if (i != 1) t[i].pre = i - 1;
if (i != n) t[i].nxt = i + 1;
}
for (rg int p, i = 1; i <= n; ++i) {
p = pos[i];
upt(i, p, t[p].pre);
upt(i, p, t[t[p].pre].pre);
upt(i, p, t[p].nxt);
upt(i, p, t[t[p].nxt].nxt);
if (t[p].pre) t[t[p].pre].nxt = t[p].nxt;
if (t[p].nxt) t[t[p].nxt].pre = t[p].pre;
t[p].pre = t[p].nxt = 0;
}
for (rg int i = 1; i <= n; ++i) {
r3[0][i] = r1[r2[i]];
if (r2[i])
dis1[0][i] = abs(t[pos[i]].h - t[pos[r2[i]]].h);
if (r1[r2[i]] && r2[i])
dis2[0][i] = abs(t[pos[r2[i]]].h - t[pos[r1[r2[i]]]].h);
}
for (rg int i = 1; i <= 19; ++i) {
for (rg int j = 1; j <= n; ++j) {
r3[i][j] = r3[i - 1][r3[i - 1][j]];
if (r3[i][j]) {
dis1[i][j] = dis1[i - 1][j] + dis1[i - 1][r3[i - 1][j]];
dis2[i][j] = dis2[i - 1][j] + dis2[i - 1][r3[i - 1][j]];
}
}
}
int X; read(X);
int ans = 0; double mn = 2e9;
for (rg int i = 1; i <= n; ++i) {
int x = i, s = X;
LL da = 0, db = 0;
for (rg int j = 19; ~j; --j) {
if (r3[j][x] && s >= dis1[j][x] + dis2[j][x]) {
da += dis1[j][x];
db += dis2[j][x];
s -= dis1[j][x] + dis2[j][x];
x = r3[j][x];
}
}
if (s >= dis1[0][x]) da += dis1[0][x];
if (da == 0) continue;
double nw = 1.0 * da / db;
if (!ans || mn - nw > eps || (fabs(mn - nw) <= eps && t[pos[i]].h > t[pos[ans]].h))
ans = i, mn = nw;
}
printf("%d\n", ans);
int m; read(m);
for (rg int x, s; m--; ) {
read(x), read(s);
LL da = 0, db = 0;
for (rg int j = 19; ~j; --j) {
if (r3[j][x] && s >= dis1[j][x] + dis2[j][x]) {
da += dis1[j][x];
db += dis2[j][x];
s -= dis1[j][x] + dis2[j][x];
x = r3[j][x];
}
}
if (s >= dis1[0][x]) da += dis1[0][x];
printf("%lld %lld\n", da, db);
}
return 0;
}

完结撒花 \(qwq\)

「NOIP2012」开车旅行的更多相关文章

  1. 【LOJ2604】「NOIP2012」开车旅行

    [题目链接] [点击打开链接] [题目大意] 从西到东的坐标轴\([1,n]\)上有\(n\)个海拔互不相同的城市,每两个城市之间的距离定义为\(dis(i,j)=|h_i-h_j|\) 小\(A\) ...

  2. Loj #3057. 「HNOI2019」校园旅行

    Loj #3057. 「HNOI2019」校园旅行 某学校的每个建筑都有一个独特的编号.一天你在校园里无聊,决定在校园内随意地漫步. 你已经在校园里呆过一段时间,对校园内每个建筑的编号非常熟悉,于是你 ...

  3. Luogu 1081 【NOIP2012】开车旅行 (链表,倍增)

    Luogu 1081 [NOIP2012]开车旅行 (链表,倍增) Description 小A 和小B决定利用假期外出旅行,他们将想去的城市从1到N 编号,且编号较小的城市在编号较大的城市的西边,已 ...

  4. 【NOIP2012】开车旅行(倍增)

    题面 Description 小A 和小B决定利用假期外出旅行,他们将想去的城市从1到N 编号,且编号较小的城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 i的海拔高度为Hi,城市 ...

  5. vijos P1780 【NOIP2012】 开车旅行

    描述 小\(A\)和小\(B\)决定利用假期外出旅行,他们将想去的城市从\(1\)到\(N\)编号,且编号较小的城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市\(i\)的海拔高度为 ...

  6. 【vijos1780】【NOIP2012】开车旅行 倍增

    题目描述 有\(n\)个城市,第\(i\)个城市的海拔为\(h_i\)且这\(n\)个城市的海拔互不相同.编号比较大的城市在东边.两个城市\(i,j\)之间的距离为\(|h_i-h_j|\) 小A和小 ...

  7. noip2012 P1081 开车旅行

    小 A 和小 B 决定利用假期外出旅行,他们将想去的城市从 1 到 N 编号,且编号较小的城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 i 的海拔高度为Hi,城市 i 和城市 j ...

  8. 【noip2012】开车旅行

    题意: 给n个点的海拔h[i](不同点海拔不同) 两点的距离为abs(h[i]-h[j]) 有a.b两人轮流开车(只能往下标大的地方开) a每次会开到里当前点第二近的点 b每次会开到离当前点最近的点( ...

  9. 「luogu3313」[SDOI2014] 旅行

    题目大意 :有 n 个城市连成一棵树, 每个城市有两个关键字, 一个是该城市的宗教, 另一个是城市的评级;旅行者要在城市间旅行, 他只会在和自己宗教相同的城市留宿;维护四个树上操作 { 1. “CC ...

随机推荐

  1. 在java的静态方法中访问类的实例成员

    直接来看代码: public class Example { int x = 3;//类的实例变量,初始化值为3 static int y = 4;//类的静态变量,初始化值为4 public sta ...

  2. 到底是哪个“O”管理内部人员风险?

    导读 俗话说,家和万事兴.与之相对的,家不睦则必自败.同理,如果缺乏明确的领导,内部人员风险管理项目或内部人威胁项目 (ITP) 也将走向失败. 俗话说,家和万事兴.与之相对的,家不睦则必自败.同理, ...

  3. 【Java excel】导出excel文件

    TestExprot package excel; import java.io.File; import java.io.IOException; import java.text.DateForm ...

  4. 洛谷 T8088 RQY的舞会

    嗯... 题目链接:https://www.luogu.org/problem/T8088 这道题很好想,我想的是维护两个小根堆(当然可以用数组模拟) 然后从堆顶开始,如果两个元素的差小于1,则cnt ...

  5. BinaryTree(二叉树)

    我认为二叉树的递归实现体现了递归思想的一些重要性质,如果对递归的理解不够的话,想利用递归来实现是很费劲的(实际上我现在都还有些懵...),虽然会用,但一些地方不能弄清楚原因. 经过几天的学习,看了许多 ...

  6. Python爬虫连载6-cookie深入使用实例化实现自动登录

    一.使用cookie登录 1.直接把cookie复制下去,然后手动放到请求头 2.http模块包含一些关于cookie的模块,通过他们我们可以自动使用cookie (1)cookieJar 管理存储c ...

  7. IDEA 解决 Maven 依赖冲突的高能神器,这一篇够不够?

    ​ 1.何为依赖冲突 Maven是个很好用的依赖管理工具,但是再好的东西也不是完美的.Maven的依赖机制会导致Jar包的冲突.举个例子,现在你的项目中,使用了两个Jar包,分别是A和B.现在A需要依 ...

  8. Page Cache(页缓存)

    Page Cache 由内存中的物理page组成,其内容对应磁盘上的block. page cache的大小是动态变化的. backing store: cache缓存的存储设备 一个page通常包含 ...

  9. Java Juc学习笔记

    Java JUC 简介 在 Java 5.0 提供了 java.util.concurrent (简称JUC )包,在此包中增加了在并发编程中很常用的实用工具类,用于定义类似于线程的自定义子系统,包括 ...

  10. Django中defer和only区别

    defer('id', 'name'):取出对象,字段除了id和name都有 only('id', 'name'):取出对象, 只有id和name ret=models.Author.objects. ...