题意:一行N个城市,有各自不同的海拔,定义两个城市之间的距离为海拔之差的绝对值,小a和小b轮流开车,开车方向从左往右,小a总是开到第二近的城市,小b开到最近的城市(如有两个城市和当前城市海拔之差相等,海拔低的更近)。当其中任一人无法按照自己的方案前进或前进后总路程超过一个上限,旅行结束。一,给定一个路程上限x0,求从哪个城市出发A和B路程比值最小,这里规定任意数比零等于无穷大,比值相等输出海拔最高的。二,给出M组询问,每组给出出发城市s和路程上限x,求A和B的路程。N<=100000,M<=10000.

最直观的思路应该是先N^2预处理在每个城市,a和b的目标是哪里,然后再O(NM)地回答询问。看一下数据范围,70分N<1000, 这个暴力的得分是相当可观的。在考场上最好不管三七二十一先写出来,因为很明显这道题并不是针对某一个成型的算法出的,正解肯定是在这个暴力基础上优化。

先观察一下这个暴力的复杂度O(N^2+MN),如果要过这道题,显然两项都要优化。对于第一项,优化比较好办,倒序扫描,将每个城市压入平衡树,对于每个海拔求一下前驱后继就行了,降为nlogn(在下无能,实在想不出类似于排序扫描之类的更优的方法)。

然后第二个环节,不难发现在每个城市,每个人的目标都各自是固定的,实现时就可以将两个人一起开一轮绑定在一起,这样一来每个城市的后两个,三个等等的目标城市都是固定的,这提示我们可以处理每个城市后面相距多个轮回的城市以加速算法。对于这种问题,比较经典的想法就是倍增(logn)或者分块(sqrt(n))。

个人感觉分块是更好写的,假设N=100000,sqrt(N)约等于350,我们就处理出每个点之后第350个城市是哪个,然后就是经典的两行代码:while(x>350)x-=350,city=next350[city],a+=..., b+=...; while(x>0)x--,city=next1[city],x+=..., b+=...;(当然实际操作中还要处理是a开车还是b开车,是否城市走完了路程限制还没消耗完这些细节)两个循环次数都在350以内,足以过最大数据了。当然,这个350只是个例子,实际操作中取根号n即可(就取350当然也不会超时。。)。

当然,分块的目的只是为了多得点分甚至水过这道题,最正统的当然还是倍增了,处理每个城市第2^k个目标点,循环的时候,指数从大到小枚举即可保证二进制位能够凑成原来的整数。但是如果实现得不是很好(向我这种),倍增完了往往到不了目标点,还需要特判并且手动往后走一下。

这题虽然理论上路程之和完全会超int,然而实践int可以过,不需要开long long,CCF真是良心数据。但是考场上一定要开long long,不能被NOIP的数据惯坏了(永远不会忘记CQOI2015送分裸题爆零的经历)。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<set>
using namespace std;
#define dis(i,j) (h[i]>h[j] ? h[i]-h[j] : h[j]-h[i])
const int MAXN = 100010;
int N, M, LG;
int h[MAXN];
int nextb[MAXN], nexta[MAXN];
#define _next(t) nextb[nexta[t]]
int ans[MAXN][2];struct City {int h, id;City(){}City(int x,int y){h=x; id=y;}bool operator < (const City&t1) const {return h < t1.h;}
};set<City> S;
set<City>::iterator it1, it2, bst;
void FindNear()//用set很容易RE,一定要多对拍一下
{nextb[N-1] = N;S.insert(City(h[N], N));S.insert(City(h[N-1], N-1));for (int i = N-2; i>0; --i){City tmp = City(h[i], i), tmp2;it1 = S.lower_bound(tmp);if (it1 == S.end()) {--it1; nextb[i] = it1->id;--it1; nexta[i] = it1->id;S.insert(tmp);continue;}if (it1 != S.begin()) {it2 = it1; --it1;if (it2->h - h[i] < h[i] - it1->h) nextb[i] = it2->id, bst = it2;else nextb[i] = it1->id, bst = it1;}else {nextb[i] = it1->id;++it1; nexta[i] = it1->id;S.insert(tmp); continue;}tmp2 = *bst;S.erase(bst);it1 = S.lower_bound(tmp);if (it1 == S.end()) { --it1; nexta[i] = it1->id; }else {if (it1 != S.begin()) {it2 = it1; --it1;if (it2->h - h[i] < h[i] - it1->h) nexta[i] = it2->id;else nexta[i] = it1->id;}else nexta[i] = it1->id;}S.insert(tmp2);S.insert(tmp);}
}int adis[MAXN][20], bdis[MAXN][20];
int dest[MAXN][20];
void Prepare()
{int i, j;for (LG=1; 2*(1<<LG)<=N; ++LG) ;for (i = 1; i<=N; ++i) {adis[i][0] = nexta[i] ? dis(i, nexta[i]) : 0;bdis[i][0] = _next(i) ? dis(nexta[i], _next(i)) : 0;dest[i][0] = _next(i);}for (i = 1; i<=LG; ++i)for (j = 1; j<=N; ++j) {dest[j][i] = dest[ dest[j][i-1] ][i-1];adis[j][i] = adis[j][i-1] + adis[ dest[j][i-1] ][i-1];bdis[j][i] = bdis[j][i-1] + bdis[ dest[j][i-1] ][i-1];}
}void drive(int s, int len, int& xa, int& xb)
{xa = xb = 0;int cur = s;for (int i = LG; i>=0; --i)if (dest[cur][i] && adis[cur][i]+bdis[cur][i]<=len) {xa += adis[cur][i];xb += bdis[cur][i];len -= adis[cur][i] + bdis[cur][i];cur = dest[cur][i];}while (1) {if (dis(nexta[cur], cur)>len || !nexta[cur]) break;xa += dis(nexta[cur], cur);len -= dis(nexta[cur], cur);cur = nexta[cur];if (dis(nextb[cur], cur)>len || !nextb[cur]) break;xb += dis(nextb[cur], cur);len -= dis(nextb[cur], cur);cur = nextb[cur];}
}int X0;
const double eps = 1e-6, DINF = 1e12;//不卡精度,double可水过
int task1()
{double best = DINF, cur;int res=0, i, xa, xb;for (i = 1; i<=N; ++i) {drive(i, X0, xa, xb);if (xb == 0 && best>=DINF-eps) {if (h[i] > h[res]) res = i;continue;}cur = (double)xa / (double)xb;if (cur < best-eps) best=cur, res=i;else if (cur>=best-eps && cur<=best+eps && h[i]>h[res])best = cur, res = i;}return res;
}int main()
{int i, s, len, xa, xb;scanf("%d", &N);for (i = 1; i<=N; ++i)scanf("%d", &h[i]);FindNear();Prepare();scanf("%d%d", &X0, &M);for (i = 1; i<=M; ++i){scanf("%d%d", &s, &len);drive(s, len, xa, xb);ans[i][0] = xa;ans[i][1] = xb;}printf("%d\n", task1());for (i = 1; i<=M; ++i)printf("%d %d\n", ans[i][0], ans[i][1]);return 0;
}

NOIP2012 开车旅行 (倍增)相关推荐

  1. NOIP2012 开车旅行

    开车旅行 (drive.cpp/c/pas) [问题描述] 小 A 和小 B 决定利用假期外出旅行,他们将想去的城市从 1 到 N 编号,且编号较小的城市在编号较大的城市的西边,已知各个城市的海拔高度 ...

  2. NOIP2012开车旅行 【倍增】

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

  3. [NOIp2012]开车旅行

    Description Luogu1081 Solution 首先可以暴力模拟走的过程即可得70分. 观察暴力效率低下的原因,其一是向前走的时候比较慢,用倍增的思路优化即可.其二是读入时处理的每个点到 ...

  4. NOIp2012开车旅行

    思路 我觉得难的是预处理,非常的麻烦:倍增比较好理解: 首先可以用线段树啊,双向链表啊,平衡树啊,二叉搜索树啊什么的(雾),我用的是set,倒序查找(因为只能走到比当前点序号要大的点),在set中查找 ...

  5. P1081 开车旅行 倍增 洛谷

    题目连接 题意 题目已经说的hin明确了. 题解 我们要求出从每个点出发,小A要走的城市和小B要走的城市. 我们把iii以后的所有点的海拔加入到set" role="present ...

  6. NOIP2012提高组 开车旅行 解题报告

    开车旅行 题目描述 样例输入 样例输出 70分算法 暴力预处理出对于每一个点他右边最近.次近的点的编号,对于每一个询问,暴力模拟开车过程即可. 100算法 和上面一样我们得预处理出每一个点最近.次近的 ...

  7. 刷题记录(NC16562 开车旅行)(树上倍增)

    NC16562 开车旅行 题目链接 关键点: 1.预处理:将所有点到达另一个点的最短和次短距离先求出 方法:利用set,从最后一个城市开始插入,每次插入到set中,查看左右是否存在有城市(即set是按 ...

  8. P1081 [NOIP2012 提高组] 开车旅行(倍增)(动态规划)

    洛谷传送门 文章目录 题目描述 解析 代码 题目描述 解析 利用倍增,设计dp慢慢敲即可... 注意距离累加在一起会爆int,需要ll 特判条件非常之复杂... 心力交瘁,就酱了 代码 #includ ...

  9. 【NOIP2012提高组】开车旅行

    Description 现在有n个城市,每个城市有它的高度 Hi H_i,保证每个 Hi H_i互不相同.我们定义两个城市之间的距离 disi,j=|Hi−Hj| dis_{i,j}=|H_i-H_j ...

最新文章

  1. 基于python的大数据分析实战学习笔记-pandas(数据分析包)
  2. python图片-python实现读取并显示图片的两种方法
  3. 天线发射功率计算公式_怎样计算天线直径发射功率卫星租用带宽
  4. 从零开始入门 K8s | 调度器的调度流程和算法介绍
  5. LeetCode(15):三数之和
  6. U-boot链接地址的详解
  7. Swift云存储特性研究
  8. python当用户输入的不是整数_当用户输入字符串而不是整数时,如何保护我的python代码?...
  9. 将Notepad++配置成Java轻量级的IDE
  10. ASP.NET MVC 个人学习笔记之 Controller传值
  11. 基于OpenCV实现人脸识别--Python
  12. mysql手动同步_MySql数据库主从手动同步
  13. 分析了 3000 份 Bug 记录,可以发现什么?
  14. 芈珺:iOS自动化测试工具总览
  15. git push或git pull等其他git命令 出现unable to access ‘https://gitee.com/你的git仓库地址)清除网络代理
  16. qt web混合编程_Qt+VS混合编程教程
  17. 『原创』老范的Bug跟踪管理系统0.1 Alpha——介绍篇
  18. MyBatis入门到精通
  19. 全球最小的一款P2P软件——eMuleBT软件框架分析
  20. 网络与IO知识扫盲(一):Linux虚拟文件系统,文件描述符

热门文章

  1. jQuery-UI draggable的参数
  2. 阿里云、保利威的点播有什么区别,哪个更好?
  3. 保利威重磅开启「828 B2B企业节 · 专场峰会 」!
  4. php文件怎么改为mp3,mgg格式怎么转换为mp3
  5. 综合实践活动信息技术小学版第三册电子课本_福建首个电子竞技专业为你开启电竞之路,圆你电竞梦想!——三明医学科技职业学院电子竞技运动与管理专业介绍...
  6. python数据可视化开发(1):Matplotlib库基础知识
  7. 2022年二级建造师建筑安装工程费用项目的组成与计算试题及答案
  8. 野餐规划(最小度限制生成树)
  9. godaddy域名注册教程
  10. android手机设计,用户钦点 最好用的Android手机就是它!