传送门

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. ZOJ1004 Anagrams by Stack

    题目大意:规定 i 为入栈,o 为出栈,现在给两个字符串st1,st2,现在要将st1转化为st2,转化方法是,st1中字符从头开始入栈,并合理出栈构造出st2.请输出所有可能的出入栈步骤. 深度优先 ...

  2. spring boot中配置文件中变量的引用

    配置文件中 变量的自身引用 ${名称} java文件中引用:非静态变量 之间在变量上面注释@Value("${名称}")  静态变量 在set方法上注释@Value("$ ...

  3. MQTT 浏览器 mqttws31.min.js

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  4. Educational Codeforces Round 82 A. Erasing Zeroes

    You are given a string ss. Each character is either 0 or 1. You want all 1's in the string to form a ...

  5. 树莓派4B踩坑指南 - (10)安装坚果云(更新:暂不支持)

    191209更新: 根据坚果云用户支持(helpdesk@nutstore.net)的官方回复,客户端不支持arm,所以本篇后续内容可以不用看了.. 原文如下: "您好,客户端似乎不支持ar ...

  6. linux 添加与修改用户归属组

    参考资源:https://cnzhx.net/blog/linux-add-user-to-group/ 一:已存在的用户 1.要以root进行登录 2.打开终端 3.修改分组 usermod -a ...

  7. Flatpak 1.5.2 即将发布

    导读 Flatpak 1.5.1开发版本为Flatpaks的受保护/经过身份验证的下载提供了初始支持,这是基础架构的工作,旨在允许Flathub或Linux上其他基于Flatpak的“应用程序商店”中 ...

  8. 从分支git clone

    git clone -b <branch> <remote_repo> 具体用法:git clone -b 分支名 https://www.xx.com/app.git 以上就 ...

  9. jquery 单选框 radio是否选择问题

    业务需求是当用户勾选中的时候删除数据,取消勾选的时候数据取消 //单选事件,获取到每行数据ID $('.checkItem').change(function(){ // checkItem是给rad ...

  10. in comment after two dashes (--) next character must be > not - (position: START_TAG seen ...

    Error executing Maven. in comment after two dashes (--) next character must be > not - (position: ...