题目

小 A 和小 B 决定利用假期外出旅行,他们将想去的城市从 1 到 N 编号,且编号较小的城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 i 的海拔高度为Hi,城市 i 和城市 j 之间的距离 d[i,j]恰好是这两个城市海拔高度之差的绝对值,即d[i,j] = |Hi− Hj|。 旅行过程中,小 A 和小 B 轮流开车,第一天小 A 开车,之后每天轮换一次。他们计划选择一个城市 S 作为起点,一直向东行驶,并且最多行驶 X 公里就结束旅行。小 A 和小 B的驾驶风格不同,小 B 总是沿着前进方向选择一个最近的城市作为目的地,而小 A 总是沿着前进方向选择第二近的城市作为目的地(注意:本题中如果当前城市到两个城市的距离相同,则认为离海拔低的那个城市更近)。如果其中任何一人无法按照自己的原则选择目的城市,或者到达目的地会使行驶的总距离超出 X 公里,他们就会结束旅行。

在启程之前,小 A 想知道两个问题:

对于一个给定的 X=X0,从哪一个城市出发,小 A 开车行驶的路程总数与小 B 行驶的路程总数的比值最小(如果小 B 的行驶路程为 0,此时的比值可视为无穷大,且两个无穷大视为相等)。如果从多个城市出发,小 A 开车行驶的路程总数与小 B 行驶的路程总数的比值都最小,则输出海拔最高的那个城市。

对任意给定的 X=Xi和出发城市 Si,小 A 开车行驶的路程总数以及小 B 行驶的路程

总数。

输入格式

第一行包含一个整数 N,表示城市的数目。

第二行有 N 个整数,每两个整数之间用一个空格隔开,依次表示城市 1 到城市 N 的海拔高度,即 H1,H2,……,Hn,且每个 Hi都是不同的。

第三行包含一个整数 X0。

第四行为一个整数 M,表示给定 M 组 Si和 Xi。

接下来的 M 行,每行包含 2 个整数 Si和 Xi,表示从城市 Si出发,最多行驶 Xi公里。

输出格式

输出共 M+1 行。

第一行包含一个整数 S0,表示对于给定的 X0,从编号为 S0的城市出发,小 A 开车行驶的路程总数与小 B 行驶的路程总数的比值最小。

接下来的 M 行,每行包含 2 个整数,之间用一个空格隔开,依次表示在给定的 Si和

Xi下小 A 行驶的里程总数和小 B 行驶的里程总数。

输入样例

4

2 3 1 4

3

4

1 3

2 3

3 3

4 3

输出样例

1

1 1

2 0

0 0

0 0

提示

对于30%的数据,有1≤N≤20,1≤M≤20;

对于40%的数据,有1≤N≤100,1≤M≤100;

对于50%的数据,有1≤N≤100,1≤M≤1,000;

对于70%的数据,有1≤N≤1,000,1≤M≤10,000;

对于100%的数据,有1≤N≤100,000,1≤M≤100,000,-1,000,000,000≤Hi≤1,000,000,000,0≤X0≤1,000,000,000,1≤Si≤N,0≤Xi≤1,000,000,000,数据保证Hi 互不相同。

题解

以前没A的一道题,今天补上

观察题意可以看出,每次开车并没有什么决策,如果可以开,那么目的地是确定的

那么可以预处理倍增,这样就可以\(O(nlogn)\)解决第一个问,\(O(mlogn)\)解决第二个问

至于预处理,如何找出之后最近的和次近的,可以用平衡树,但常数略大

考虑直接排序,那么每个点最近的点一定在其左右两格以内,拿出来比较一下就好

但从左到右访问,访问过的点不能作为之后的点的目的地【即只能向右开】,访问完删掉就好了,用双向链表实现

代码略丑

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define LL long long int
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define Redge(u) for (int k = h[u]; k; k = ed[k].nxt)
using namespace std;
const int maxn = 100005,maxm = 100005,INF = 0x7fffffff;
const LL inf = 10000000000000000ll;
inline int read(){
int out = 0,flag = 1; char c = getchar();
while (c < 48 || c > 57) {if (c == '-') flag = -1; c = getchar();}
while (c >= 48 && c <= 57) {out = (out << 1) + (out << 3) + c - '0'; c = getchar();}
return out * flag;
}
int n,m,h[maxn],nxt[2][maxn],to[maxn][20];
int id[maxn],ls[maxn],rs[maxn],temp[10],cnt;
LL cost[2][maxn][20];
inline bool cmp(const int& a,const int& b){return h[a] < h[b];}
void init(){
sort(id + 1,id + 1 + n,cmp);
for (int i = 1; i <= n; i++){
if (i != 1) ls[id[i]] = id[i - 1];
if (i != n) rs[id[i]] = id[i + 1];
}
for (int i = 1; i <= n; i++){
cnt = 0;
int j = ls[i],gmin = INF,nmin = INF,a = 0,b = 0;
if (ls[j]) temp[++cnt] = ls[j],temp[++cnt] = j;
else if (j) temp[++cnt] = j;
j = rs[i];
if (rs[j]) temp[++cnt] = j,temp[++cnt] = rs[j];
else if (j) temp[++cnt] = j;
for (j = 1; j <= cnt; j++){
int d = abs(h[i] - h[temp[j]]);
if (d < gmin){
nmin = gmin; gmin = d;
a = b; b = temp[j];
}
else if (d < nmin){
nmin = d; a = temp[j];
}
}
nxt[0][i] = a;
nxt[1][i] = b;
if (ls[i]) rs[ls[i]] = rs[i];
if (rs[i]) ls[rs[i]] = ls[i];
}
for (int i = 1; i <= n; i++){
if (nxt[1][nxt[0][i]]){
to[i][1] = nxt[1][nxt[0][i]];
cost[0][i][1] = abs(h[nxt[0][i]] - h[i]);
cost[1][i][1] = abs(h[nxt[1][nxt[0][i]]] - h[nxt[0][i]]);
}else cost[0][i][1] = cost[1][i][1] = inf;
}
for (int t = 2; t <= 18; t++){
for (int i = 1; i <= n; i++){
if (to[to[i][t - 1]][t - 1]){
to[i][t] = to[to[i][t - 1]][t - 1];
cost[0][i][t] = cost[0][i][t - 1] + cost[0][to[i][t - 1]][t - 1];
cost[1][i][t] = cost[1][i][t - 1] + cost[1][to[i][t - 1]][t - 1];
}else cost[0][i][t] = cost[1][i][t] = inf;
}
}
}
void solve1(){
int X = read(),u = 0,d,now;
double ca,cb,ma,mb;
for (int i = 1; i <= n; i++){
d = X; ca = 0; cb = 0; now = i;
for (int j = 18; j; j--)
if (to[now][j] && cost[0][now][j] + cost[1][now][j] <= d){
d -= cost[0][now][j] + cost[1][now][j];
ca += cost[0][now][j];
cb += cost[1][now][j];
now = to[now][j];
}
if (nxt[0][now] && abs(h[nxt[0][now]] - h[now]) <= d)
ca += abs(h[nxt[0][now]] - h[now]);
if (!u || (cb == 0 && mb == 0 && h[i] > h[u]) || (mb == 0 && cb != 0) || (cb != 0 && (ca / cb < ma / mb || (fabs(ca / cb - ma / mb) < 1e-9 && h[i] > h[u]))))
u = i,ma = ca,mb = cb;
}
printf("%d\n",u);
}
void solve2(){
m = read();
int x,now,ca,cb;
while (m--){
now = read(); x = read(); ca = cb = 0;
for (int i = 18; i; i--){
if (to[now][i] && cost[0][now][i] + cost[1][now][i] <= x){
x -= cost[0][now][i] + cost[1][now][i];
ca += cost[0][now][i];
cb += cost[1][now][i];
now = to[now][i];
}
}
if (nxt[0][now] && fabs(h[nxt[0][now]] - h[now]) <= x)
ca += (int)fabs(h[nxt[0][now]] - h[now]);
printf("%d %d\n",ca,cb);
}
}
int main(){
n = read();
for (int i = 1; i <= n; i++) h[i] = read(),id[i] = i;
init();
solve1();
solve2();
return 0;
}

NOIP2012开车旅行 【倍增】的更多相关文章

  1. P1081 [NOIP2012]开车旅行[倍增]

    P1081 开车旅行    题面较为啰嗦.大概概括:一个数列,只能从一个点向后走,两种方案:A.走到和自己差的绝对值次小的点B.走到和自己差的绝对值最小点:花费为此差绝对值:若干询问从规定点向后最多花 ...

  2. Luogu1081 NOIP2012 开车旅行 倍增

    题目传送门 为什么NOIP的题目都这么长qwq 话说2012的D1T3和D2T3都是大火题啊qwq 预处理神题 对于这种跳跳跳的题目考虑使用倍增优化枚举.先预处理某个点之后距离最小和次小的城市,然后倍 ...

  3. 洛谷1081 (NOIp2012) 开车旅行——倍增预处理

    题目:https://www.luogu.org/problemnew/show/P1081 预处理从每个点开始a能走多少.b能走多少.可以像dp一样从后往前推. 但有X的限制.所以该数组可以变成倍增 ...

  4. Cogs 1264. [NOIP2012] 开车旅行(70分 暴力)

    1264. [NOIP2012] 开车旅行 ★★☆   输入文件:drive.in   输出文件:drive.out   简单对比时间限制:2 s   内存限制:128 MB [题目描述] 小A 和小 ...

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

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

  6. $Noip2012\ Luogu1081$ 开车旅行 倍增优化$ DP$

    Luogu Description Sol 1.发现对于每个城市,小A和小B的选择是固定的,可以预处理出来,分别记为ga[],gb[] 2.并且,只要知道了出发城市和出发天数,那么当前城市和小A,小B ...

  7. luogu1081 [NOIp2012]开车旅行 (STL::multiset+倍增)

    先用不管什么方法求出来从每个点出发,A走到哪.B走到哪(我写了一个很沙雕的STL) 然后把每个点拆成两个点,分别表示A从这里出发和B从这里出发,然后连边是要A连到B.B连到A.边长就是这次走的路径长度 ...

  8. 【NOIP2012提高组】开车旅行 倍增

    题目分析 朴素的做法就是预处理下一个目的地,然后跑模拟,超时. 本题最重要的考点是倍增优化.设$fa[i][j]$表示a从i出发行驶$2^j$“次”后行驶的路程,$fb[i][j]$表示从i出发行驶$ ...

  9. noip2012开车旅行 题解

    题目大意: 给出n个排成一行的城市,每个城市有一个不同的海拔.定义两个城市间的距离等于他们的高度差的绝对值,且绝对值相等的时候海拔低的距离近.有两个人轮流开车,从左往右走.A每次都选最近的,B每次都选 ...

随机推荐

  1. 01_13_Struts_默认Action

    01_13_Struts_默认Action 1. 配置struts默认Action <package name="default" namespace="/&quo ...

  2. 【转】VxWorks信号量分析

    Wind内核中有二进制信号量.计数信号量和互斥信号量三种类型,为了是运用程序具有可移植性,还提供了POSIX(可移植操作系统接口)信号量 .在VxWorks中,信号量是实现任务同步的主要手段,也是解决 ...

  3. 【转】MFC编辑框自动换行,垂直滚动条自动下移

    1.新建一个编辑框控件(Edit Control),将其多行(Multiline)前面打勾(属性设置为True),Auto HScroll前面的勾去掉(属性设置False),这样就可以实现每一行填满后 ...

  4. Unity基础-脚本的优化

    脚本的优化 object pool 避免频繁的内存分配和gc噩梦(字符串相加?) 是否有必要都写在update里?分帧? 需要的只取一次 使用editor内赋值,而不是find 复杂的物理 复杂的数学 ...

  5. W3CPLUS DEMO一些有意思的效果备份

    时间轴轮播图: http://www.w3cplus.com/w3cplusDemo/demos/timeline.html css3各种图标效果: http://www.w3cplus.com/w3 ...

  6. 微软与百度合作:win10搜索引擎默认百度

    全球最大的中文搜索引擎百度公司与微软公司共同宣布双方展开战略合作.百度并将成为中国市场上Windows 10 Microsoft Edge浏览器的默认主页和搜索引擎.也就是说,将来人们在win10的M ...

  7. python的标准模块

    本文用于记录python中的标准模块,随时更新. decimal模块(解决小数循环问题): >>> import decimal >>> a = decimal.D ...

  8. LeetCode(215) Kth Largest Element in an Array

    题目 Find the kth largest element in an unsorted array. Note that it is the kth largest element in the ...

  9. HDU 1827 强连通 缩点 Summer Holiday

    求出强连通分量,因为强连通中只要有一个人被通知到了,所有人都能被通知到. 缩点以后形成一个DAG,找出那些入度为0的点,累加上它们的权值就是答案.一个点的权值等于SCC中权值最小的那个点. #incl ...

  10. SpringBoot接收前端参数的三种方法

    都是以前的笔记了,有时间就整理出来了,SpringBoot接收前端参数的三种方法,首先第一种代码: @RestController public class ControllerTest { //访问 ...