P1081 开车旅行    题面较为啰嗦。大概概括:一个数列,只能从一个点向后走,两种方案:A.走到和自己差的绝对值次小的点B.走到和自己差的绝对值最小点;花费为此差绝对值;若干询问从规定点向后最多花费$X$,且以移动方式A开始每走一次切换一次方式。求以A、B方式各花费多少。


不看题解切紫题一遍过了,兴奋~然而连想带写花了四小时左右,真要在noip考场上怕不是要凉。。。我太菜了QwQ

先看第一问,找比值最小点,实际上就是拆成$N$个询问,扔到第二问的询问里面做掉的说。所以主要看对于询问点怎么向后找终止点。可以猜出应该是$O(\log N)$一次询问,所以就要求高效的跳法。

考虑A若干次之后走到后面一个点,从这个点继续走,这样一个状态,很多询问都可能经历。所以对于一个点,希望预处理出以他为起点有关的信息。

维护从他开始的终点?显然不行。

若最远点$T_0$,可能当下到这起点已花了一些代价,由于代价制限导致走不到最远,大概能走到$T_1 < T_0$。也就是说,$S\sim T_1$这一段是我可以走过的,$T_1$之后都到不了。

所以可以根据实际情况二分查找最远点。实现起来,就是个倍增,到目标点要走$k$次,总是可以拆成走二的指数幂次叠加,枚举当前走的$2^i$次,可行就跳,不可行就呆原地。

这个是处理询问的方法。所以瓶颈就在于如何预处理倍增数组。坑死我了。

设计状态$fa[i][j],fb[i][j],to[i][j]$表示从$i$点出发,走$2^j$次,A、B各自花费,以及讫点。

对于底层$to[i][0]$,只采用A方式移动,找出后面次小代价即可。单独处理。

对于次底层$f[i][1]$,开始用AB轮流交替方式移动,所以在底层要顺便处理以B方式移动一次的相关信息,在这一层与A合并。

之后,由于每个状态都是走偶数次的,涉及转移状态都是以A开始的,比如我移动4次,由前2次和后2次拼接,这两段都是以A开始的。所以直接合并即可。

提一下最底层找相邻点的几种方法:

  • 每个点后面离他最近的。。前驱后继?平衡树?考虑用set来替代。找出大于他的两个,小于他的两个(没有则设为0),排一下序处理出来
  • set找4个点同上,然后。。分类讨论。。我的弱智方法。。。。qwq
  • 双向链表。可以将数组排序,将其用数组模拟成链表,之后,和每个点相邻的,虽然不一定是原来数组中他后面的元素,但是对于原数组1号,他在排序数组中相邻的肯定是前驱后继。找出之后将之从链表中删除,再考虑原数组的2号点,这时就不存在1号点的干扰了,后面同理。

常数稍大,但不影响能过,反正都是$O((N+M)\log N)$的。相关细节注意一下即可,如超出1e9提前特判掉等等。

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<cmath>
  5. #include<algorithm>
  6. #include<set>
  7. #define dis first
  8. #define pos second
  9. #define dbg(x) cerr<<#x<<" = "<<x<<endl
  10. #define _dbg(x,y) cerr<<#x<<" = "<<x<<" "<<#y<<" = "<<y<<endl
  11. using namespace std;
  12. typedef pair<int,int> pii;
  13. typedef long long ll;
  14. template<typename T>inline char MIN(T&A,T B){return A>B?A=B,:;}
  15. template<typename T>inline char MAX(T&A,T B){return A<B?A=B,:;}
  16. template<typename T>inline T _min(T A,T B){return A<B?A:B;}
  17. template<typename T>inline T _max(T A,T B){return A>B?A:B;}
  18. namespace io{
  19. const int SIZE = ( << ) + ;
  20. char ibuf[SIZE], *iS, *iT, obuf[SIZE], *oS = obuf, *oT = oS + SIZE - , c, qu[]; int f, qr;
  21. #define gc() (iS == iT ? (iT = (iS = ibuf) + fread (ibuf, 1, SIZE, stdin), (iS == iT ? EOF : *iS ++)) : *iS ++)
  22. inline void flush (){fwrite (obuf, , oS - obuf, stdout);oS = obuf;}
  23. inline void putc (char x){*oS ++ = x;if (oS == oT) flush ();}
  24. template <class I>
  25. inline void read(I &x) {for (f = , c = gc(); c < '' || c > ''; c = gc()) if (c == '-') f = -;
  26. for (x = ; c <= '' && c >= ''; c = gc()) x = x * + (c & ); x *= f;}
  27. template <class I>
  28. inline void print (I x){
  29. if (!x) putc (''); if (x < ) putc ('-'), x = -x;while(x) qu[++ qr] = x % + '', x /= ;while (qr) putc (qu[qr--]);}
  30. struct Flusher_ {~Flusher_(){flush();}}io_flusher_;
  31. }
  32. using io::read;
  33. using io::putc;
  34. using io::print;
  35. const int N=+,INF=0x3f3f3f3f;
  36. set<pii> s;
  37. int h[N],fa[N][],fb[N][],to[N][],to2[N],disb[N];
  38. int n,Q,T,m;
  39.  
  40. inline void preprocess_the_bottom(){
  41. set<pii>::iterator up,down;
  42. int d0,d1,d2,d3,p0,p1,p2,p3;
  43. m=__lg(n);
  44. fa[n][]=fb[n][]=disb[n]=;to[n][]=to2[n]=n+;s.insert(make_pair(h[n],n));
  45. for(register int i=n-;i;--i){
  46. down=up=s.lower_bound(make_pair(h[i],));
  47. d0=d1=d2=d3=,p0=p1=p2=p3=n+;
  48. if(down!=s.begin())--down,d0=h[i]-(*down).dis,d0>1e9?(d0=):(p0=(*down).pos);//下侧第一
  49. if(down!=s.begin())--down,d2=h[i]-(*down).dis,d2>1e9?(d2=):(p2=(*down).pos);//下侧第二
  50. if(up!=s.end())d1=(*up).dis-h[i],d1>1e9?(d1=):(p1=(*up).pos);//上侧第一
  51. if(up!=s.end()&&++up!=s.end())d3=(*up).dis-h[i],d3>1e9?(d3=):(p3=(*up).pos);//上侧第二
  52. if(d0){
  53. if(d1){//两侧都有
  54. if(d1<d0){
  55. disb[i]=d1,to2[i]=p1;
  56. if(d3&&d3<d0)fa[i][]=d3,to[i][]=p3;//上侧第二为次近
  57. else fa[i][]=d0,to[i][]=p0;//下侧第一为次近
  58. }
  59. else{
  60. disb[i]=d0,to2[i]=p0;
  61. if(d2&&d2<=d1)fa[i][]=d2,to[i][]=p2;//下侧第二为次近
  62. else fa[i][]=d1,to[i][]=p1;//上侧第一为次近
  63. }
  64. }
  65. else{//只有下侧
  66. disb[i]=d0,to2[i]=p0;
  67. fa[i][]=d2,to[i][]=p2;
  68. }
  69. }
  70. else disb[i]=d1,to2[i]=p1,fa[i][]=d3,to[i][]=p3;//只有上侧或者两侧都没有
  71. // dbg(i);_dbg(disb[i],to2[i]);_dbg(fa[i][0],to[i][0]);
  72. s.insert(make_pair(h[i],i));
  73. }
  74. to2[n+]=n+;for(register int i=;i<=m;++i)to[n+][i]=n+;
  75. }
  76.  
  77. inline void preprocess(){
  78. for(register int i=;i<=n;++i)fa[i][]=fa[i][],fb[i][]=disb[to[i][]],to[i][]=to2[to[i][]];
  79. for(register int i=;i<=m;++i){
  80. for(register int j=;j<=n;++j){
  81. fa[j][i]=fa[j][i-]+fa[to[j][i-]][i-],fb[j][i]=fb[j][i-]+fb[to[j][i-]][i-];to[j][i]=to[to[j][i-]][i-];
  82. fa[j][i]+0ll+fb[j][i]>1e9?(fa[j][i]=,fb[j][i]=,to[j][i]=n+):;
  83. }
  84. }
  85. }
  86. int xa,xb;
  87. inline void Query(int x,int tot){
  88. xa=xb=;
  89. for(register int i=m;~i;--i)if(to[x][i]<=n&&fa[x][i]+fb[x][i]<=tot)tot-=fa[x][i]+fb[x][i],xa+=fa[x][i],xb+=fb[x][i],x=to[x][i];
  90. }
  91. int x,tot,p,q,ans;
  92. int main(){//freopen("test.in","r",stdin);freopen("test.out","w",stdout);
  93. read(n);for(register int i=;i<=n;++i)read(h[i]);
  94. preprocess_the_bottom();preprocess();
  95. read(Q);Query(,Q);p=xa,q=xb,ans=;
  96. for(register int i=;i<=n;++i){
  97. Query(i,Q);
  98. if(!xb){if(!q)if(h[ans]<h[i])ans=i;continue;}
  99. if(xa*1ll*q<xb*1ll*p)p=xa,q=xb,ans=i;
  100. else if(xa*1ll*q==xb*1ll*p)if(h[ans]<h[i])ans=i;
  101. }
  102. print(ans);read(T);putc('\n');
  103. for(register int i=;i<=T;++i){
  104. read(x),read(tot);Query(x,tot);
  105. print(xa),putc(' '),print(xb),putc('\n');
  106. }
  107. return ;
  108. }

P1081 [NOIP2012]开车旅行[倍增]的更多相关文章

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

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

  2. Luogu1081 NOIP2012 开车旅行 倍增

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

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

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

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

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

  5. NOIP2012开车旅行 【倍增】

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

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

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

  7. P1081 开车旅行[倍增](毒瘤题)

    其实就是个大模拟. 首先,根据题意,小A和小B从任意一个城市开始走,无论\(X\)如何,其路径是一定唯一的. 显然对于两问都可以想出一个\(O(n^2)\)的暴力,即直接一步一步地向右走. 首先,我们 ...

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

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

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

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

随机推荐

  1. 关于ckeditor在IE下出现不兼容的问题

    今天在用ckeditor时在ie下测试出现了不兼容问题,样式,字体等属性设置不了. 后来在html标签上方添加了: <!DOCTYPE html PUBLIC "-//W3C//DTD ...

  2. 【C/C++】assert()函数用法总结

    assert()函数用法总结 assert宏的原型定义在<assert.h>中,其作用是如果它的条件返回错误,则终止程序执行,原型定义: #include <assert.h> ...

  3. Java架构师 成长之路 -- 跳出程序员陷阱(转载)

    本人也是coding很多年,虽然很失败,但也总算有点失败的心得,不过我在中国,大多数程序员都是像我一样,在一直走着弯路. 如果想成为一个架构师,就必须走正确的路,否则离目标越来越远,正在辛苦工作的程序 ...

  4. Java程序员的职业发展道路 附:大型网站 -- 架构技能图谱(Java版)

    职业发展道路基本有3条: 第一条路线(技术专精): 初级Java开发---中级--高级---项目主管--Java项目经理---网站架构师----资深专家 第二条路线(技术转产品):初级Java开发-- ...

  5. java中怎么调用python 脚本

    调用方法: import java.io.BufferedReader; import java.io.InputStreamReader; public class PythonInvoke { p ...

  6. python 爬虫 urllib模块 反爬虫机制UA

    方法: 使用urlencode函数 urllib.request.urlopen() import urllib.request import urllib.parse url = 'https:// ...

  7. Java中String连接性能的分析

    总结:如果String的数量小于4(不含4),使用String.concat()来连接String,否则首先计算最终结果的长度,再用该长度来创建一个StringBuilder,最后使用这个String ...

  8. 菜鸟系列Fabric——Fabric 1.2 多机部署(3)

    多机部署fabric kafka共识 1. 角色分配 主机1 主机 2 Org1 peer0 1 Org2 peer 0 1 Orderer 0 1 Orderer 2 kafka 0 1 kafka ...

  9. PTA(Basic Level)1036.跟奥巴马一起编程

    美国总统奥巴马不仅呼吁所有人都学习编程,甚至以身作则编写代码,成为美国历史上首位编写计算机代码的总统.2014 年底,为庆祝"计算机科学教育周"正式启动,奥巴马编写了很简单的计算机 ...

  10. java-selenium三种等待方式

    方式1: 线程等待:Thread.sleep(xxxx) 只要在case中加入sleep就会强制等待设置的时间后才会执行之后的命令,这种等待一般适用于调试脚本的时候. java代码 //等待3秒 Th ...