其实就是个大模拟。

首先,根据题意,小A和小B从任意一个城市开始走,无论\(X\)如何,其路径是一定唯一的。

显然对于两问都可以想出一个\(O(n^2)\)的暴力,即直接一步一步地向右走。

首先,我们当然需要知道A,B在每个城市的下一步如何走,记\(nexta(i),nextb(i)\)为A,B在\(i\)处时,下一步走到的城市编号。

考虑如何高效(复杂度小于等于\(O(nlogn)\))维护两个\(next\)。

显然不能直接维护每个城市与其后面的城市的差值,再好的数据结构也会到\(O(n^2)\)。

不妨考虑从后往前依次插入\(H_i\),然后动态维护\(H_i\sim H_n\)的有序集合。这样的话,在有序集合中,最小的差值一定要么是\(H_i\)与其前驱,要么就是与其后继的差值。次小的差值,就是\(H_i\)前驱、前驱的前驱、后继、后继的后继与\(H_i\)的差值的次小值。这个问题,平衡树解决之,预处理\(O(nlogn)\)。

下面考虑走\(k\)步的情况,当前步是A走还是B走与步数的奇偶性有关,因此我们还要分开讨论。

那么,我们不妨考虑以此为基础进行优化,比如优化到\(O(nlogn)\)。显然地,对于这样的问题,我们可以倍增预处理,\(O(logn)\)询问。

接下来考察我们需要什么信息,分别是\(i\)向后走\(k\)步的城市,A和B从\(i\)向后走\(k\)步的路程。

设\(f[0/1][i][j]\)为从\(i\)位置,0A,1B向后走\(2^j\)步的城市。

显然

\[f[0][i][0]=nexta(i)\\f[1][i][0]=nextb(i)
\]

由于,走\(2^0\)步是走奇数步,有转移

\[f[0][i][1]=f[1][f[0][i][0]][0]\\f[1][i][1]=f[0][f[1][i][0]][0]
\]

对于走\(2^j\)步,有

\[f[0][i][j]=f[0][f[0][i][j-1]][j-1]\\f[1][i][j]=f[1][f[1][i][j-1]][j-1]
\]

设\(da[0/1][i][j]\)表示从\(i\)位置,A向后走\(2^j\)步的路程,且现在(当前步)是0A,1B在开车,还没走时的A开的距离

显然

\[da[0][i][0]=dist(i,nexta(i))\\da[1][i][0]=0
\]

有转移

\[da[0][i][1]=da[0][i][0]+da[1][f[0][i][0]][0]\\da[1][i][1]=da[1][i][0]+da[0][f[1][i][0]][0]\\da[0][i][j]=da[0][i][j-1]+da[0][f[0][i][j-1]][j-1]\\da[1][i][j]=da[1][i][j-1]+da[1][f[1][i][j-1]][j-1]
\]

设\(db[0/1][i][j]\)表示从\(i\)位置,B向后走\(2^j\)步的路程,且现在是0A,1B在开车。

跟\(da\)差别不大,不再赘述。

预处理完成之后,我们开始考虑题述问题。

对于第一问,对给出的\(X_0\),我们枚举城市\(S_i\),倍增统计走\(X_0\)步的答案(当然超出\(N\)要特判),\(O(nlogn)\)解决之。

对于第二问,同样的,对于每一组\(S_i,X_i\),直接倍增统计即可,复杂度\(O(mlogn)\)。

总复杂度在\(O((n+m)logn)\)左右,完全可以通过本题。

注意,这道题的细节之数量足以让人去世。

代码未经重构,很丑。

参考代码

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<cmath>
  5. #include<algorithm>
  6. #include<string>
  7. #include<cstdlib>
  8. #include<queue>
  9. #include<set>
  10. #include<map>
  11. #include<vector>
  12. #define INF 0x7fffffff
  13. #define PI acos(-1.0)
  14. #define N 100010
  15. #define MOD 2520
  16. #define E 1e-12
  17. #define ll long long
  18. using namespace std;
  19. inline ll read()
  20. {
  21. ll f=1,x=0;char c=getchar();
  22. while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
  23. while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
  24. return x*f;
  25. }
  26. set<int> h;
  27. map<int,int> mp;
  28. int t;
  29. ll n,a[N],na[N],nb[N],f[2][N][21],da[2][N][21],db[2][N][21];
  30. int main()
  31. {
  32. n=read();t=log2(n);
  33. for(int i=1;i<=n;++i) a[i]=read();
  34. a[0]=INF,a[n+1]=-INF;
  35. h.insert(INF);
  36. h.insert(-INF);
  37. mp[-INF]=0,mp[INF]=n+1;
  38. for(int i=n;i>=1;--i){
  39. h.insert(a[i]);mp[a[i]]=i;
  40. ll n1=((++h.find(a[i])!=h.end())?(*++h.find(a[i])):INF),n2=(((++(++h.find(a[i])))!=h.end())?(*++(++h.find(a[i]))):INF);
  41. ll p1=((h.find(a[i])!=h.begin())?(*--h.find(a[i])):-INF),p2=((--h.find(a[i])!=h.end())?(*--(--h.find(a[i]))):-INF);
  42. if(n1-a[i]>=a[i]-p1){
  43. nb[i]=mp[p1];
  44. na[i]=(n1-a[i]>=a[i]-p2)?mp[p2]:mp[n1];
  45. }
  46. else{
  47. nb[i]=mp[n1];
  48. na[i]=(n2-a[i]>=a[i]-p1)?mp[p1]:mp[n2];
  49. }
  50. f[0][i][0]=na[i];f[1][i][0]=nb[i];
  51. da[0][i][0]=abs(a[i]-a[na[i]]);
  52. db[1][i][0]=abs(a[i]-a[nb[i]]);
  53. }
  54. for(int j=1;j<=t;++j){
  55. for(int i=1;i<=n;++i){
  56. if(j==1){
  57. f[0][i][1]=f[1][f[0][i][0]][0];
  58. f[1][i][1]=f[0][f[1][i][0]][0];
  59. da[0][i][1]=da[0][i][0]+da[1][f[0][i][0]][0];
  60. da[1][i][1]=da[1][i][0]+da[0][f[1][i][0]][0];
  61. db[0][i][1]=db[0][i][0]+db[1][f[0][i][0]][0];
  62. db[1][i][1]=db[1][i][0]+db[0][f[1][i][0]][0];
  63. }else{
  64. f[0][i][j]=f[0][f[0][i][j-1]][j-1];
  65. f[1][i][j]=f[1][f[1][i][j-1]][j-1];
  66. da[0][i][j]=da[0][i][j-1]+da[0][f[0][i][j-1]][j-1];
  67. da[1][i][j]=da[1][i][j-1]+da[1][f[1][i][j-1]][j-1];
  68. db[0][i][j]=db[0][i][j-1]+db[0][f[0][i][j-1]][j-1];
  69. db[1][i][j]=db[1][i][j-1]+db[1][f[1][i][j-1]][j-1];
  70. }
  71. }
  72. }/
  73. int x0=read(),s0=0;
  74. double ans=1e14,nans=1e14;//task 1
  75. for(int i=1;i<=n;++i){
  76. int now=i;
  77. ll resa=0,resb=0;
  78. for(int j=t;j>=0;--j){
  79. if(f[0][now][j]){
  80. if(resa+resb+da[0][now][j]+db[0][now][j]>x0)
  81. continue;
  82. resa+=da[0][now][j];resb+=db[0][now][j];
  83. now=f[0][now][j];
  84. }
  85. }
  86. nans=(double)resa/(double)resb;
  87. if(nans<ans){
  88. ans=nans,s0=i;
  89. }
  90. else{
  91. if(nans==ans&&a[s0]<a[i]) s0=i;
  92. }
  93. }
  94. printf("%d\n",s0);
  95. int m=read();//task 2
  96. while(m--){
  97. ll si=read(),xi=read();
  98. ll resa=0,resb=0,now=si;
  99. for(int j=t;j>=0;--j){
  100. if(f[0][now][j]){
  101. if(resa+resb+da[0][now][j]+db[0][now][j]>xi)
  102. continue;
  103. resa+=da[0][now][j];resb+=db[0][now][j];
  104. now=f[0][now][j];
  105. }
  106. }
  107. printf("%lld %lld\n",resa,resb);
  108. }
  109. return 0;
  110. }

P1081 开车旅行[倍增](毒瘤题)的更多相关文章

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  8. P1081 开车旅行

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

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

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

随机推荐

  1. Python(一)对 meta class 的理解

    1. 理解  class 对于 class 来说,表示一个代码块规定了实例化后的 object 的属性和方法 但是在 Python 中,class 本身也是对象.定义一个 class,就相当于在内存中 ...

  2. cad 一个小技巧--复制视口带冻结信息

    cad使用 ctrl+c 和 ctrl+v 进行跨文件复制视口的时候,会出现复制视口冻结信息丢失,因为你只选择了视口进行复制, 如果要实现带上冻结信息,那么要把含有相关图层的图元一起 ctrl+c/v ...

  3. Kafka支持单集群20万分区

    Kafka支持单集群20万分区 之前网上关于确定Kafka分区数的博客多多少少都源自于饶军大神的文章,如今他带来了这方面的第二篇文章,特此翻译一下,记录一下其中的要点. 原贴地址: https://w ...

  4. | C语言I作业01

    C语言I作业01 标签:18软件 李煦亮 1.1 你对软件工程专业了解是怎样? 对软件工程的了解是从人工智能频繁地出现在各大新闻,新闻报道了许多高校针对人工智能开设了相关课程或者专业,软件工程是开设的 ...

  5. 宝塔webhook配合码云,本地git push 服务器自动pull

    emmmm,这其实是一个很简单的一件事情,但是有很多坑,记录一下 先大概讲一下原理吧,就是每次您 push 代码后,都会给远程 HTTP URL 发送一个 POST 请求 更多说明 » 然后在宝塔这边 ...

  6. Laravel学习记录

    1. stream 下载响应 response()->streamDownload(function (){ echo "test" // 输出 },'文件名');

  7. Spark Core知识点复习-2

    day1112 1.spark core复习 任务提交 缓存 checkPoint 自定义排序 自定义分区器 自定义累加器 广播变量 Spark Shuffle过程 SparkSQL 一. Spark ...

  8. 开源规则引擎 Drools 学习笔记 之 -- 1 cannot be cast to org.drools.compiler.kie.builder.impl.InternalKieModule

    直接进入正题 我们在使用开源规则引擎 Drools 的时候, 启动的时候可能会抛出如下异常: Caused by: java.lang.ClassCastException: cn.com.cheng ...

  9. 推送一个docker 使用阿里docker hub

    阿里docker hub 地址 打开容器镜像服务页https://cr.console.aliyun.com/cn-qingdao/namespaces 这个是我的私有库 配置加速 我这边用的也是阿里 ...

  10. 【WPF】2、美化控件

    控件有默认样式,但是有时候默认样式并不够用,就需要美化. 1.常用的方法是美术出图,直接贴图进去,效果又好又简单(对程序来说). 用图片有三种方式:设置控件背景图片.设置控件内容为图片和直接使用图片做 ...