题目

到处都有

闲话

碰巧考场上出了 \(Noip\) 原题

然后这题自然而然想到

预处理一个点开始分别由 \(A,B\) 驾驶会走到的下一个点

然后用预处理的数组求答案

当然你会发现 \(X=X0\) 这一问和后面的问的解法没什么区别

这都不是重点

\(ccf\) 很良心给暴力 \(70\) 分

然后 \(100\) 分码得非常开心

解法一

没错,就是按闲话的思路

求下一个点 \(O(n^2)\) 可以做到,往后扫一遍依题算即可

然后对于每个询问暴力一步一步走知道无路可走

竟然给 \(70\) !

\(Code\)

  1. #include<cstdio>
  2. #include<algorithm>
  3. #define LL long long
  4. using namespace std;
  5. const int N = 1e5 + 5;
  6. int n, m, h[N], nxt[N][2];
  7. struct node{int a, b;};
  8. void getNext()
  9. {
  10. h[0] = 0x3f3f3f3f;
  11. for(register int i = 1; i <= n; i++)
  12. {
  13. int k1 = 0, k2 = 0;
  14. for(register int j = i + 1; j <= n; j++)
  15. {
  16. int z = abs(h[i] - h[j]);
  17. if (z < abs(h[i] - h[k1]) || (z == abs(h[i] - h[k1]) && h[j] < h[k1])) k2 = k1, k1 = j;
  18. else if (z == abs(h[i] - h[k1]) || z < abs(h[i] - h[k2]) || (z == abs(h[i] - h[k2]) && h[j] < h[k2])) k2 = j;
  19. }
  20. nxt[i][1] = k1, nxt[i][0] = k2;
  21. }
  22. }
  23. inline node solve(int S, int X)
  24. {
  25. int p = 0, x = 0;
  26. node ret = {0, 0};
  27. while (nxt[S][p] != 0 && x + abs(h[S] - h[nxt[S][p]]) <= X)
  28. {
  29. if (!p) ret.a += abs(h[S] - h[nxt[S][p]]);
  30. else ret.b += abs(h[S] - h[nxt[S][p]]);
  31. x += abs(h[S] - h[nxt[S][p]]), S = nxt[S][p], p ^= 1;
  32. }
  33. return ret;
  34. }
  35. inline double calc(int x, int y)
  36. {
  37. if (!y) return 0x3f3f3f3f;
  38. return 1.0 * x / y;
  39. }
  40. int main()
  41. {
  42. scanf("%d", &n);
  43. for(register int i = 1; i <= n; i++) scanf("%d", &h[i]);
  44. getNext();
  45. LL S, X;
  46. scanf("%d", &X);
  47. int k = 0; double ans = 0x3f3f3f3f;
  48. for(register int i = 1; i <= n; i++)
  49. {
  50. node t = solve(i, X);
  51. if (calc(t.a, t.b) < ans || (calc(t.a, t.b) == ans && h[i] > h[k]))
  52. ans = calc(t.a, t.b), k = i;
  53. }
  54. printf("%d\n", k);
  55. scanf("%d", &m);
  56. for(; m; m--)
  57. {
  58. scanf("%lld%lld", &S, &X);
  59. node t = solve(S, X);
  60. printf("%d %d\n", t.a, t.b);
  61. }
  62. }

解法二

没错,就是按照解法一的思路

首先我们发现一步一步跳太低效

也太给人灵感

一步一步跳?好熟悉?!

那就倍增啊

\(2\) 的幂次跳就是快!!

然后这不是最关键的地方

因为预处理还卡在 \(O(n^2)\)

相当于什么都没干

所以我们总得干点什么

是的

预处理实际上非常好玩

你可以用排序+链表非常常规地搞出来

当然,你可以更常规用平衡树来搞搞

我选择了后者(当然不可能手打平衡树,\(set\) 就是好)

这东西比较繁琐,要慢慢讨论

收获

用 \(set\) 如果涉及多个关键字怎么办?

这样定义

  1. #include<set>
  2. using namespace std;
  3. struct nod{int h, id;};
  4. struct cmp{bool operator()(const nod &a, const nod &b){return a.h < b.h;}};
  5. set<nod, cmp> s;

于是我们申明了一个节点为 \(nod\) 类型的平衡树

那么各类使用参数也相应的改变

你会发现 \(h\) 是第一关键字

那它在比较时会先比较第一关键字,再比较第二关键字

学会了!

哦,\(AC\) 代码记录一波

  1. #include<cstdio>
  2. #include<algorithm>
  3. #include<set>
  4. #define LL long long
  5. using namespace std;
  6. const int N = 1e5 + 5;
  7. int n, m, h[N], nxt[N][2];
  8. LL F[N][20], A[N][20], B[N][20];
  9. struct node{LL a, b;};
  10. struct nod{int h, id;};
  11. struct cmp{bool operator()(const nod &a, const nod &b){return a.h < b.h;}};
  12. set<nod, cmp> tr;
  13. set<nod, cmp>::iterator it, itt;
  14. inline void swap(nod &x, nod &y){nod t; t = x, x = y, y = t;}
  15. void getNext()
  16. {
  17. tr.insert(nod{h[n], n});
  18. for(register int i = n - 1; i; i--)
  19. {
  20. nod k1 = {0x3f3f3f3f, 0}, k2 = {0x3f3f3f3f, 0};
  21. it = tr.lower_bound(nod{h[i], i});
  22. if (it == tr.begin())
  23. {
  24. k1 = *it;
  25. if (++it != tr.end()) k2 = *it;
  26. }
  27. else if (it == tr.end())
  28. {
  29. k1 = *(--it);
  30. if (it != tr.begin()) k2 = *(--it);
  31. }
  32. else{
  33. itt = it, --it;
  34. int count = 0; nod l = *it, r = *itt;
  35. while (1)
  36. {
  37. if (abs(h[i] - l.h) < abs(h[i] - r.h) || (abs(h[i] - l.h) == abs(h[i] - r.h) && l.h < r.h))
  38. {
  39. if (!count)
  40. {
  41. k1 = l, ++count;
  42. if (it == tr.begin()){l = {0x3f3f3f3f, 0}; continue;}
  43. l = *(--it);
  44. }
  45. else{k2 = l; break;}
  46. }
  47. else{
  48. if (!count)
  49. {
  50. k1 = r, ++count, r = *(++itt);
  51. if (itt == tr.end()) r = {0x3f3f3f3f, 0};
  52. }
  53. else{k2 = r; break;}
  54. }
  55. }
  56. }
  57. if (abs(h[i] - k1.h) > abs(h[i] - k2.h) || (abs(h[i] - k1.h) == abs(h[i] - k2.h) && k1.h > k2.h)) swap(k1, k2);
  58. nxt[i][1] = k1.id, nxt[i][0] = k2.id;
  59. tr.insert(nod{h[i], i});
  60. }
  61. }
  62. void getF()
  63. {
  64. for(register int i = 1; i <= n; i++)
  65. F[i][0] = nxt[nxt[i][0]][1],
  66. A[i][0] = abs(h[i] - h[nxt[i][0]]),
  67. B[i][0] = abs(h[nxt[i][0]] - h[nxt[nxt[i][0]][1]]);
  68. for(register int j = 1; j <= 17; j++)
  69. for(register int i = 1; i <= n; i++)
  70. F[i][j] = F[F[i][j - 1]][j - 1],
  71. A[i][j] = A[i][j - 1] + A[F[i][j - 1]][j - 1],
  72. B[i][j] = B[i][j - 1] + B[F[i][j - 1]][j - 1];
  73. }
  74. inline node solve(int S, LL X)
  75. {
  76. int p = 0; LL x = 0;
  77. node ret = {0, 0};
  78. for(register int i = 17; i >= 0; i--)
  79. if (F[S][i] && x + A[S][i] + B[S][i] <= X)
  80. {
  81. ret.a += A[S][i], ret.b += B[S][i];
  82. x += A[S][i] + B[S][i], S = F[S][i];
  83. }
  84. while (nxt[S][p] && x + abs(h[S] - h[nxt[S][p]]) <= X)
  85. {
  86. if (!p) ret.a += abs(h[S] - h[nxt[S][p]]);
  87. else ret.b += abs(h[S] - h[nxt[S][p]]);
  88. x += abs(h[S] - h[nxt[S][p]]), S = nxt[S][p], p ^= 1;
  89. }
  90. return ret;
  91. }
  92. inline double calc(int x, int y)
  93. {
  94. if (!y) return 0x3f3f3f3f;
  95. return 1.0 * x / y;
  96. }
  97. int main()
  98. {
  99. scanf("%d", &n);
  100. for(register int i = 1; i <= n; i++) scanf("%d", &h[i]);
  101. getNext(), getF();
  102. int S; LL X;
  103. scanf("%lld", &X);
  104. int k = 0; double ans = 0x3f3f3f3f;
  105. for(register int i = 1; i <= n; i++)
  106. {
  107. node t = solve(i, X);
  108. if (calc(t.a, t.b) < ans || (calc(t.a, t.b) == ans && h[i] > h[k]))
  109. ans = calc(t.a, t.b), k = i;
  110. }
  111. printf("%d\n", k);
  112. scanf("%d", &m);
  113. for(; m; m--)
  114. {
  115. scanf("%d%lld", &S, &X);
  116. node t = solve(S, X);
  117. printf("%lld %lld\n", t.a, t.b);
  118. }
  119. }

【NOIP2012提高组】开车旅行的更多相关文章

  1. [NOIP2012提高组]开车旅行

    题目:洛谷P1081.Vijos P1780.codevs1199. 题目大意:有n座海拔高度不相同的城市(编号1~n),两城市的距离就是两城市海拔之差.规定每次只能从编号小的城市走到编号大的城市. ...

  2. 刷题总结——疫情控制(NOIP2012提高组)

    题目: 题目背景 NOIP2012 提高组 DAY2 试题. 题目描述 H 国有 n 个城市,这 n 个城市用 n-1 条双向道路相互连通构成一棵树,1 号城市是首都,也是树中的根节点. H 国的首都 ...

  3. GZOJ 1361. 国王游戏【NOIP2012提高组DAY1】

    国王游戏[NOIP2012提高组DAY1] Time Limit:1000MS Memory Limit:128000K Description 国王游戏(game.cpp/c/pas) [问题描述] ...

  4. 【NOIP2015模拟11.5】JZOJ8月5日提高组T3 旅行

    [NOIP2015模拟11.5]JZOJ8月5日提高组T3 旅行 题目 若不存在第\(k\)短路径时,输出"Stupid Mike" 题解 题意 给出一个有\(n\)个点的树 问这 ...

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

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

  6. NOIP2012 提高组 Day 1

    期望得分:100+100+70=270 实际得分:100+50+70=220 T2 没有底 最后剩余时间来不及打高精.思路出现错误 T1 Vigenère 密码 题目描述 16 世纪法国外交家 Bla ...

  7. [NOIP2012] 提高组 洛谷P1084 疫情控制

    题目描述 H 国有 n 个城市,这 n 个城市用 n-1 条双向道路相互连通构成一棵树,1 号城市是首都, 也是树中的根节点. H 国的首都爆发了一种危害性极高的传染病.当局为了控制疫情,不让疫情扩散 ...

  8. [NOIP2012] 提高组 洛谷P1080 国王游戏

    题目描述 恰逢 H 国国庆,国王邀请 n 位大臣来玩一个有奖游戏.首先,他让每个大臣在左.右 手上面分别写下一个整数,国王自己也在左.右手上各写一个整数.然后,让这 n 位大臣排 成一排,国王站在队伍 ...

  9. [NOIP2012] 提高组 洛谷P1083 借教室

    题目描述 在大学期间,经常需要租借教室.大到院系举办活动,小到学习小组自习讨论,都需要向学校申请借教室.教室的大小功能不同,借教室人的身份不同,借教室的手续也不一样. 面对海量租借教室的信息,我们自然 ...

  10. [NOIP2012] 提高组 洛谷P1082 同余方程

    题目描述 求关于 x 的同余方程 ax ≡ 1 (mod b)的最小正整数解. 输入输出格式 输入格式: 输入只有一行,包含两个正整数 a, b,用一个空格隔开. 输出格式: 输出只有一行,包含一个正 ...

随机推荐

  1. Zabbix与乐维监控对比分析(一)——架构、性能篇

    近年来,Zabbix凭借其近乎无所不能的监控及优越的性能一路高歌猛进,在开源监控领域独占鳌头:而作为后起的新锐IT监控平台--乐维监控,则不断吸收Zabbix,Prometheus等优秀开源平台的优点 ...

  2. C++编程笔记(多线程学习)

    目录 一.线程创建 二.线程的相关操作 2.1 join 2.2 detach 2.3 joinable 三.线程参数 3.1传参所引发的资源回收问题 3.2 将对象的成员函数作为入口函数 四.线程的 ...

  3. Golang反射修改变量值

    1. 前言 前面的随笔Golang反射获取变量类型和值分享了如何通过反射获取变量的类型和值, 也就是Golang反射三大定律中的前两个,即从interface{}到反射对象和从反射对象到interfa ...

  4. 【每日一题】【双指针/栈/reverse】2022年2月19日-判断是否为回文字符串

    给定一个长度为 n 的字符串,请编写一个函数判断该字符串是否回文.如果是回文请返回true,否则返回false.   字符串回文指该字符串正序与其逆序逐字符一致.   数据范围:0 < n \l ...

  5. C++面向对象程序设计期末复习笔记[吉林大学](结合历年题速成85)

    1.头文件 头文件的作用就是被其他的.cpp包含进去的.它们本身并不参与编译,但实际上,它们的内容却在多个.cpp文件中得到了编译.根据"定义只能一次"原则我们知道,头文件中不能放 ...

  6. jQuery事件与动态效果

    目录 一:阻止后续事件执行 1.推荐使用阻止事件 2.未使用 阻止后续事件执行 3.使用阻止后续事件执行 二:阻止事件冒泡 1.什么是事件冒泡? 2.未阻止事件冒泡 3.阻止事件冒泡 4.2.阻止冒泡 ...

  7. 微服务系列之服务监控 Prometheus与Grafana

    1.为什么需要监控服务   监控服务的所属服务器硬件(如cpu,内存,磁盘I/O等)指标.服务本身的(如gc频率.线程池大小.锁争用情况.请求.响应.自定义业务指标),对于以前的小型单体服务来说,确实 ...

  8. Linux下“减速”查看日志的方法

    Linux下"减速"查看日志的方法 需求场景 今天查看日志,有个需求,需要按照指定"速率"输出日志信息到终端屏幕上,方便查看. 这个需求日常应该也经常会碰到,比 ...

  9. [数据结构]普里姆(Prim)算法生成最小生成树

    前提介绍:最小生成树概念 一个连通图的生成树是图的极小连通子图,它包含图中的所有定点,并且只含尽可能少的边,这意味着对于生成树来说,就砍去使生成树变成非连通图:若给它怎家一条边就会形成图中的一条回路. ...

  10. NG-Alain + Angular11使用ModalHelper实现简单版本弹框,代码超级少,记得模块要引用这个组件

    先看一下目录结构 --aa-item ----modal-compment ------modal-compment.component.html ------modal-compment.compo ...