题目

双向链表+倍增+模拟。

\(70pts\):

说白了此题的暴力就是细节较多的模拟题。

我们设离\(i\)城市最近的点的位置为\(B[i]\),第二近的位置为\(A[i]\)。设\(A\)或\(B\)数组等于\(0\)的的情况不能接下去走到第二或第一近的位置。

  1. 处理到底能不能继续向下走,即当前城市下一步无法选择城市时,可以直接设置该城市到0城市(即走不到)的距离为正无穷,这样接下来向下走就肯定超过规定路程。
  2. 在求第一问比值的时候注意精度问题和无穷大问题。

\(100pts\):

对70分做法进行优化。用双向链表\(O(n)\)初始化求出\(A\)数组和\(B\)数组。

因为有方向这个限制,因此每次从小到大求完A、B数组之后都要删除求完之后的节点。

倍增的时候用4个数组。

\(C[i][j]:\)表示从i出发,\(A,B\)都走了\(1<<j\)步所到达的位置。

\(disa[i][j]、b、c\)分别表示\(A,B\)都走了\(1<<j\)步\(a\)走过的距离、\(b\)走过的距离、\(c\)走过的总距离。

距离的倍增递推式为:

\(disa[i][j] = disa[i][j - 1] + disa[C[i][j - 1]][j - 1];\)

\(disb[i][j] = disb[i][j - 1] + disb[C[i][j - 1]][j - 1];\)

\(disc[i][j] = disa[i][j] + disb[i][j];\)

#include <bits/stdc++.h>
#define N 300101
#define int long long
using namespace std;
int n, m, x0, ans0, data[N], pos[N], b[N], a[N];
int C[N][20], disa[N][20], disb[N][20], disc[N][20];
//C是a,b都走了1<<j步所到达的位置,disa是a走了1<<j步所行驶的距离。
struct dat {
int id, h, l, r;//l, r都是当前数组里的值
}da[N];
int d(int x, int i)
{
if (x <= 0 || x > n || i <= 0 || i > n) return 21474836400000007;
return abs(data[x] - data[i]);
}
int d_new(int x, int i)
{
if (da[x].id <= 0 || da[x].id > n || da[i].id <= 0 || da[i].id > n) return 2147483640000007;
return abs(da[x].h - da[i].h);
}
bool cmp(dat a, dat b)
{
return a.h < b.h;
}
inline void isrt(int i, int j)
{
int minn = d_new(pos[i], pos[b[i]]);
int minn2 = d_new(pos[i], pos[a[i]]);
int ha = d_new(pos[i], j);
if (ha < minn || (ha == minn && data[da[j].id] < data[b[i]]) )
{
a[i] = b[i];
b[i] = da[j].id;
}
else if (ha < minn2 || (ha == minn2 && data[da[j].id] < data[a[i]]) )
a[i] = da[j].id;
}
inline void init()
{
scanf("%lld", &n);
for (int i = 1; i <= n; i++)
da[i].id = i, scanf("%lld", &da[i].h), data[i] = da[i].h;
sort(da + 1, da + 1 + n, cmp);
for (int i = 1; i <= n; i++)
{
pos[da[i].id] = i;
if (i != 1)
da[i].l = i - 1;
if (i != n)
da[i].r = i + 1; //最小值,次小值,一定在这四个位置中各选择一个数。
}
// pos[i]为当前结构体中的位置
for (int i = 1; i <= n; i++)
{
int now = pos[i];
int l_1, l_2, r_1, r_2;
l_1 = da[now].l;
l_2 = da[l_1].l;
r_1 = da[now].r;
r_2 = da[r_1].r;
//更新i点的最近点和第二近点
isrt(i, l_1);
isrt(i, l_2);
isrt(i, r_1);
isrt(i, r_2);
//删除了i这个点
if (da[pos[i]].l)
da[da[pos[i]].l].r = da[pos[i]].r;
if (da[pos[i]].r)
da[da[pos[i]].r].l = da[pos[i]].l;
}
for (int i = 1; i <= n; i++)
{
disa[i][0] = d(a[i], i);
disb[i][0] = d(a[i], b[a[i]]);
disc[i][0] = disa[i][0] + disb[i][0];
C[i][0] = b[a[i]];//c走一次。说明a先走一次,b再走一次。
}
for (int j = 1; j <= 19; j++)
for (int i = 1; i <= n; i++)
{
C[i][j] = C[C[i][j - 1]][j - 1];
if (C[i][j])//如果该位置还能继续走
{
disa[i][j] = disa[i][j - 1] + disa[C[i][j - 1]][j - 1];
disb[i][j] = disb[i][j - 1] + disb[C[i][j - 1]][j - 1];
disc[i][j] = disa[i][j] + disb[i][j];
}
} }
void s1()
{
int x0, mink = 0;
long double minn = 2147483648787887.0000000000;
scanf("%lld%lld", &x0, &m);
for (int o = 1; o <= n; o++)
{
int x = x0, s = o, ansa = 0, ansb = 0;
for (int i = 19; i >= 0; i--)
{
if (disc[s][i] <= x && disc[s][i])
{
x -= disc[s][i];
ansa += disa[s][i];
ansb += disb[s][i];
s = C[s][i];
}
}
if (disa[s][0] <= x && a[s])//a能走就走走
ansa += disa[s][0];
long double ha = 0;
if (ansb == 0) ha = 2147483648788.00000000000000;//设为无穷大
else ha = (long double)(1.0 * ansa / ansb);
if( ha - minn < -0.0000000001 || (ha - minn <= -0.0000000001 && data[o] > data[mink]) )
minn = min(minn, ha), mink = o;
}
printf("%lld\n", mink);
}
void s2()
{
while (m--)
{
int x, s, now, ansa = 0, ansb = 0;
scanf("%lld%lld", &s, &x);
for (int i = 19; i >= 0; i--)
{
if (disc[s][i] <= x && disc[s][i])
{
x -= disc[s][i];
ansa += disa[s][i];
ansb += disb[s][i];
s = C[s][i];
}
}
if (disa[s][0] <= x && a[s])//a能走就走走
ansa += disa[s][0];
printf("%lld %lld\n", ansa, ansb);
}
}
signed main()//倍增优化链表,双向链表
{
init();
s1();
s2();
return 0;
}

洛谷P1081 开车旅行的更多相关文章

  1. 洛谷 P1081 开车旅行(70)

    P1081 开车旅行 题目描述 小AA 和小BB 决定利用假期外出旅行,他们将想去的城市从 11到 NN 编号,且编号较小的城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 ii的海 ...

  2. [NOIP2012] 提高组 洛谷P1081 开车旅行

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

  3. NOIP 2012 洛谷P1081 开车旅行

    Description: 就是两个人开车,只能向东开.向东有n个城市,城市之间的距离为他们的高度差.A,B轮流开车,A喜欢到次近的城市,B喜欢到最近的城市.如果车子开到底了或者车子开的路程已经超过了限 ...

  4. 洛谷 P1081 开车旅行 —— 倍增

    题目:https://www.luogu.org/problemnew/show/P1081 真是倍增好题! 预处理:f[i][j] 表示从 i 点开始走 2^j 次 AB (A,B各走一次)到达的点 ...

  5. 2018.11.04 洛谷P1081 开车旅行(倍增)

    传送门 思路简单码量超凡? 感觉看完题大家应该都知道是倍增sbsbsb题了吧. 首先预处理出从每个点出发如果是AAA走到哪个点,如果是BBB走到哪个点. 然后利用刚刚预处理出的信息再预处理从每个点出发 ...

  6. 洛谷P1081 开车旅行(倍增)

    题意 题目链接 Sol 咕了一年的题解.. 并不算是很难,只是代码有点毒瘤 \(f[i][j]\)表示从\(i\)号节点出发走了\(2^j\)轮后总的距离 \(da[i][j]\)同理表示\(a\)的 ...

  7. 洛谷P1081 开车旅行70分

    https://www.luogu.org/problem/show?pid=1081 太遗憾了明明写出来了,却把最小值初始值弄小了,从第二个点开始就不可能对了.70分! #include<io ...

  8. 洛谷 P1081 开车旅行【双向链表+倍增】

    倍增数组的20和N写反了反复WAWAWA-- 注意到a和b在每个点上出发都会到一个指定的点,所以这样构成了两棵以n点为根的树 假设我们建出了这两棵树,对于第一问就可以枚举起点然后倍增的找出ab路径长度 ...

  9. 洛谷P1081——开车旅行

    传送门:QAQQAQ 题意注意点: 1.是从前往后走,不能回头 2.小A小B轮流开,先小A开,而小A是到第二近的点(这点调试的时候查了好久) 3.若绝对值差相同海拔低的更近,而第一个询问若比值相同是海 ...

随机推荐

  1. (四) Docker 使用Let's Encrypt 部署 HTTPS

    参考并感谢 周花卷 https://www.jianshu.com/p/5afc6bbeb28c 下载letsencrypt镜像(不带tag标签则表示下载latest版本) docker pull q ...

  2. Windows双系统

    基础概念 基础概念 Legacy:传统BIOS传输模式启动顺序:开机→BIOS初始化→BIOS自检→引导操作系统→进入系统.传统硬盘引导记录为MBR格式,MBR无法支持超过2T的硬盘.但拥有最好的兼容 ...

  3. MySQL计算相邻两行某列差值的方法

    简述 博主最近因工作任务缠身,都无暇顾及到我的这片自留地了.前段时间稍有空闲,花了较多的精力学习<啊哈算法>,从中学习到很多之前没有太注重的内容,收益颇丰.但是这些算法题目还没有看完,等后 ...

  4. PcAnywhere用法

    安装软件 配置被控端 点击"主机",点击"添加" 可以使用"现有的Windows账户",也可以创建新的"用户名和密码" ...

  5. 捡回reset的未提交修改

    使用 Reflog 如果一開始沒有記下來 Commit 的 SHA-1 值也沒關係,Git 裡有個 reflog 指令有保留一些紀錄.再次借用上個章節的例子,但這次我改用 --hard 模式來進行 r ...

  6. Python爬虫系列:五、正则表达式

    1.了解正则表达式 正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符.及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑. 正则表达式 ...

  7. MySQL数据库入门到高薪培训教程(从MySQL 5.7 到 MySQL 8.0)

    一.MySQL数据库入门到高薪培训视频教程(从MySQL5.7到MySQL8.0) 本套MySQL学习教程地址: https://edu.51cto.com/course/18034.html 为满足 ...

  8. while 格式化输出 运算符 字符编码

    流程控制之while循环 条件循环:while,语法如下 while 条件: # 循环体 # 如果条件为真,那么循环体则执行,执行完毕后再次循环,重新判断条件... # 如果条件为假,那么循环体不执行 ...

  9. 泛微 e-cology OA 远程代码执行漏洞复现

    0x00 前言 Poc已在github公开,由于环境搭建较为复杂,所以我在空间搜索引擎中找了国外的网站进行复现 如果有想自行搭建环境复现的可以在公众号内回复“泛微环境”即可获取源码及搭建方式 0x01 ...

  10. 两个好的k8s周边项目,mark

    这段时间没有应用, 但应该过段时间就可以派上用场了. 1,像写shell脚本一样写一个operator. https://github.com/flant/shell-operator 2,多集群的k ...