传送门

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. 【模板】凸包向内推进求不严格的半平面交——poj3384

    想不明白这题写严格的半平面交为什么会错 /* 凸包所有边向内推进r */ #include<iostream> #include<cstring> #include<cs ...

  2. python 切片技巧

    说明: 字符串[开始索引:结束索引:步长] 开始索引:从指定位置开始截取: 结束索引:从指定位置结束截取,但不包含该位置的字符. 步长:不指定时步长为1: 1)当步长为正数时候,那么切片是从左到右进行 ...

  3. idea 导入svn中java WEB项目

    1.打开idea 2.填写svn路径 3.指定本地路径 4.选择1.8 format 5.添加jdk 6.配置tomcat启动项目 File -- Project Structure

  4. Codeforces Round #600 (Div. 2) - D. Harmonious Graph(并查集)

    题意:对于一张图,如果$a$与$b$连通,则对于任意的$c(a<c<b)$都有$a$与$c$连通,则称该图为和谐图,现在给你一张图,问你最少添加多少条边使图变为和谐图. 思路:将一个连通块 ...

  5. iOS 开发中常用的排序(冒泡、选择、快速、插入、希尔、归并、基数)算法

    1.冒泡排序: 冒泡算法是一种基础的排序算法,这种算法会重复的比较数组中相邻的两个元素.如果一个元素比另一个元素大(小),那么就交换这两个元素的位置.重复这一比较直至最后一个元素.这一比较会重复n-1 ...

  6. .NET Runtime at IP 791F7E06 (79140000) with exit code 80131506.

    事件類型: 錯誤 事件來源: .NET Runtime 事件類別目錄: 無 事件識別碼: 1023 日期: 2015/12/15 時間: 上午 10:18:52 使用者: N/A 電腦: KM-ERP ...

  7. MySQL 之单表查询

    数据库数据: # (1) 创建数据表 create table employee( id int primary key auto_increment, emp_name char(12) not n ...

  8. Go安装gRPC

    grpc-go的官方安装命令 go get google.golang.org/grpc 无法正常使用. 我们可以用以下的命令替代,达到同样的效果 git clone https://github.c ...

  9. 为PHP开发搭建环境

    为了能在自己的电脑上(mac OS系统)开始编写PHP代码并完成运行,需要有: 1.安装Web服务器 2.安装PHP 3.安装数据库,比如MySQL 4.一个PHP的IDE 为了上面所提到的1~3步的 ...

  10. mapreduce课上测试

    今天上课的时候进行了一个mapreduce的实验,但是由于课下对于mapreduce还有hive的理解不够透彻,因此导致了课上没能完成这次实验. 关于本次课堂上的实验的内容大致为: 1.对一个70k的 ...