「NOIP2012」开车旅行
传送门
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」开车旅行的更多相关文章
- 【LOJ2604】「NOIP2012」开车旅行
[题目链接] [点击打开链接] [题目大意] 从西到东的坐标轴\([1,n]\)上有\(n\)个海拔互不相同的城市,每两个城市之间的距离定义为\(dis(i,j)=|h_i-h_j|\) 小\(A\) ...
- Loj #3057. 「HNOI2019」校园旅行
Loj #3057. 「HNOI2019」校园旅行 某学校的每个建筑都有一个独特的编号.一天你在校园里无聊,决定在校园内随意地漫步. 你已经在校园里呆过一段时间,对校园内每个建筑的编号非常熟悉,于是你 ...
- Luogu 1081 【NOIP2012】开车旅行 (链表,倍增)
Luogu 1081 [NOIP2012]开车旅行 (链表,倍增) Description 小A 和小B决定利用假期外出旅行,他们将想去的城市从1到N 编号,且编号较小的城市在编号较大的城市的西边,已 ...
- 【NOIP2012】开车旅行(倍增)
题面 Description 小A 和小B决定利用假期外出旅行,他们将想去的城市从1到N 编号,且编号较小的城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 i的海拔高度为Hi,城市 ...
- vijos P1780 【NOIP2012】 开车旅行
描述 小\(A\)和小\(B\)决定利用假期外出旅行,他们将想去的城市从\(1\)到\(N\)编号,且编号较小的城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市\(i\)的海拔高度为 ...
- 【vijos1780】【NOIP2012】开车旅行 倍增
题目描述 有\(n\)个城市,第\(i\)个城市的海拔为\(h_i\)且这\(n\)个城市的海拔互不相同.编号比较大的城市在东边.两个城市\(i,j\)之间的距离为\(|h_i-h_j|\) 小A和小 ...
- noip2012 P1081 开车旅行
小 A 和小 B 决定利用假期外出旅行,他们将想去的城市从 1 到 N 编号,且编号较小的城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 i 的海拔高度为Hi,城市 i 和城市 j ...
- 【noip2012】开车旅行
题意: 给n个点的海拔h[i](不同点海拔不同) 两点的距离为abs(h[i]-h[j]) 有a.b两人轮流开车(只能往下标大的地方开) a每次会开到里当前点第二近的点 b每次会开到离当前点最近的点( ...
- 「luogu3313」[SDOI2014] 旅行
题目大意 :有 n 个城市连成一棵树, 每个城市有两个关键字, 一个是该城市的宗教, 另一个是城市的评级;旅行者要在城市间旅行, 他只会在和自己宗教相同的城市留宿;维护四个树上操作 { 1. “CC ...
随机推荐
- Sqlmap 工具用法详解
Sqlmap 工具用法详解 sqlmap是一款自动化的sql注入工具. 1.主要功能:扫描.发现.利用给定的url的sql注入漏 ...
- 9000端口号被上一个ip地址占用,需要reboot才可以恢复正常ip端口问题
比如查看端口# lsof -i:9000 本机ip已经修改为192.168.0.50,而经过# lsof -i:9000查看到,端口是这样的,192.168.0.88:9000,显示的还是上一个ip的 ...
- CSS样式的引入&区别&权重&CSS层叠性&CSS样式的来源
CSS样式的引入: 内部样式: 内部样式:写在当前页面style标签中的样式 内联样式:写在style属性中的样式 外部样式: link标签引入的CSS文件 @import引入的CSS文件,需要写在c ...
- JAVA面向对象解决实际问题实例(一)
某次战役中,为便于信息交互,我军侦察部门将此次战役的关键高地坐标设定为(x=0,y=0)并规定,每向东增加100米,x加1,每向北增加100米,y加1.同时,我军情报部门也破译了敌军向坦克发送的指挥信 ...
- 操作系统OS - 同步和异步,阻塞和非阻塞
同步和异步关注的是消息通信机制,阻塞/非阻塞是程序在等待调用结果(消息,返回值)时的状态
- 误删Django的model中的表解决办法
误删Django的model中的表解决办法 1.model里面的表格实际的操作都在migrations文件夹中,里面记录了操作过程,当在database和model中删除表格时要注意初始化数据库时会报 ...
- String_Java
1.substring() 方法返回字符串的子字符串. 语法 public String substring(int beginIndex)//返回第beginIndex个字符以后的子字符串 或 pu ...
- 小程序中data数据的处理方法总结
wxml代码: <view class="container"> <view wx:for="{{list}}" wx:key="t ...
- vue中配置sass(包含vue-cli 3)
目录 vue vue cli 3 老版本的脚手架搭建的项目 版本 安装 不用修改任何配置 vue文件中使用 vue 更新时间: 2018-09-21 vue cli 3 选择 Manually sel ...
- 设计模式课程 设计模式精讲 2-4 UML类图讲解 对比讲解 demo
1 主要内容 1.1 关联和依赖的对比 1.2 组合和聚合的对比 1.3 继承和实现的对比 1.4 各种关系代码实现demo 1 主要内容 1.1 关联和依赖的对比 关联是a类中存在b类对象,企鹅类中 ...