题目描述

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

  小A和小B要开车去旅行。小A先开,他们会轮流开车。小A会把车开到第二近的城市,小B会把车开到最近的城市。如果当前城市到两个城市的距离相同,则认为海拔低的城市比较近。他们只会把车往东边开(即编号大的那边)。

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

  他还会问你\(m\)次。每次要你求出对给定的\(x=x_i\) 和出发城市\(s_i\),小A开车行驶的路程总数以及小B行驶的路程总数。

  \(n\leq 100000,m\leq 10000\)

题解

  先用set求出当前在第\(i\)个城市时小A会把车开到哪个城市和小B会把车开到那个城市。

  然后倍增。\(fa_{i,j}\)表示当前在第\(i\)个城市时开\(2^j\)轮(小A和小B各开一次算一轮)后小A开车的距离,\(f_b{i,j}\)表示当前在第\(i\)个城市时开\(2^j\)轮后小B开车的距离。\(g_{i,j}\)表示当前在第\(i\)个城市时开\(2^j\)轮后会到达哪里。

  现在我们要求当前在第\(s\)个城市,开不超过\(x\)公里,小A开车的路程和小B开车的路程。显然直接倍增就可以了,还要加上不满一轮的情况,即开若干轮后小A再开一次。

  第一问直接枚举起点,计算答案。

  第二问直接计算答案。

  时间复杂度:\(O((n+m)\log n)\)

代码

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<algorithm>
  4. #include<cstdlib>
  5. #include<ctime>
  6. #include<utility>
  7. #include<set>
  8. #include<cmath>
  9. using namespace std;
  10. typedef long long ll;
  11. typedef unsigned long long ull;
  12. typedef pair<int,int> pii;
  13. typedef pair<ll,int> pli;
  14. ll h[100010];
  15. set<pli> ht;
  16. int na[100010];
  17. int nb[100010];
  18. ll fa[100010][20];
  19. ll fb[100010][20];
  20. int g[100010][20];
  21. int getmin(ll v)
  22. {
  23. if(ht.size()==0)
  24. return -1;
  25. set<pli>::iterator p=ht.lower_bound(pli(v,0));
  26. if(p==ht.begin())
  27. return p->second;
  28. if(p==ht.end())
  29. {
  30. p--;
  31. return p->second;
  32. }
  33. pii s1=*p;
  34. s1.first-=v;
  35. p--;
  36. pii s2=*p;
  37. s2.first=v-s2.first;
  38. if(s1.first<s2.first)
  39. return s1.second;
  40. return s2.second;
  41. }
  42. struct p
  43. {
  44. int x;
  45. double s;
  46. };
  47. double inf=1e100;
  48. int main()
  49. {
  50. freopen("vijos1780.in","r",stdin);
  51. freopen("vijos1780.out","w",stdout);
  52. int n;
  53. scanf("%d",&n);
  54. int i,j;
  55. for(i=1;i<=n;i++)
  56. scanf("%lld",&h[i]);
  57. for(i=n;i>=1;i--)
  58. {
  59. nb[i]=getmin(h[i]);
  60. if(nb[i]==-1)
  61. na[i]=-1;
  62. else
  63. {
  64. ht.erase(ht.find(pii(h[nb[i]],nb[i])));
  65. na[i]=getmin(h[i]);
  66. ht.insert(pii(h[nb[i]],nb[i]));
  67. }
  68. ht.insert(pii(h[i],i));
  69. }
  70. for(i=1;i<=n;i++)
  71. if(na[i]==-1)
  72. {
  73. g[i][0]=i;
  74. fa[i][0]=fb[i][0]=0;
  75. }
  76. else if(nb[na[i]]==-1)
  77. {
  78. g[i][0]=na[i];
  79. fa[i][0]=abs(h[i]-h[na[i]]);
  80. fb[i][0]=0;
  81. }
  82. else
  83. {
  84. g[i][0]=nb[na[i]];
  85. fa[i][0]=abs(h[i]-h[na[i]]);
  86. fb[i][0]=abs(h[na[i]]-h[nb[na[i]]]);
  87. }
  88. for(j=1;j<=19;j++)
  89. for(i=1;i<=n;i++)
  90. {
  91. g[i][j]=g[g[i][j-1]][j-1];
  92. fa[i][j]=fa[i][j-1]+fa[g[i][j-1]][j-1];
  93. fb[i][j]=fb[i][j-1]+fb[g[i][j-1]][j-1];
  94. }
  95. int k;
  96. ll x0;
  97. scanf("%lld",&x0);
  98. p ans;
  99. ans.x=-1;
  100. for(i=1;i<=n;i++)
  101. {
  102. ll sa=0,sb=0;
  103. j=i;
  104. ll s=0;
  105. for(k=19;k>=0;k--)
  106. if(fa[j][k]+fb[j][k]+s<=x0)
  107. {
  108. s+=fa[j][k]+fb[j][k];
  109. sa+=fa[j][k];
  110. sb+=fb[j][k];
  111. j=g[j][k];
  112. }
  113. if(na[j]!=-1&&s+abs(h[j]-h[na[j]])<=x0)
  114. sa+=abs(h[j]-h[na[j]]);
  115. double si;
  116. if(!sb)
  117. si=inf;
  118. else
  119. si=double(sa)/sb;
  120. if(ans.x==-1||si<ans.s||(si==ans.s&&h[i]>h[ans.x]))
  121. {
  122. ans.x=i;
  123. ans.s=si;
  124. }
  125. }
  126. printf("%d\n",ans.x);
  127. int m;
  128. scanf("%d",&m);
  129. for(i=1;i<=m;i++)
  130. {
  131. int x;
  132. ll x0;
  133. scanf("%d%lld",&x,&x0);
  134. j=x;
  135. ll s=0;
  136. ll sa=0,sb=0;
  137. for(k=19;k>=0;k--)
  138. if(fa[j][k]+fb[j][k]+s<=x0)
  139. {
  140. s+=fa[j][k]+fb[j][k];
  141. sa+=fa[j][k];
  142. sb+=fb[j][k];
  143. j=g[j][k];
  144. }
  145. if(na[j]!=-1&&s+abs(h[j]-h[na[j]])<=x0)
  146. sa+=abs(h[j]-h[na[j]]);
  147. printf("%lld %lld\n",sa,sb);
  148. }
  149. return 0;
  150. }

【vijos1780】【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. NOIP2012开车旅行 【倍增】

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

  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. RPM包制作过程(一)

    本机环境:centos7,64位 1. 首先安装工具,rpmbuild可能在rpmdevtools里已经包含 #yum install rpm-devel.x86_64 #yum install rp ...

  2. Beta阶段团队成员贡献分分配规则

    Beta阶段团队成员贡献分分配规则 Alpha阶段贡献分分配有些负责,在这里进行一些修改: 对任务完成得分部分进行了简化 对发现bug的惩罚措施进行了修改 移除了优化得分,不鼓励修改他人代码 移除了帮 ...

  3. Python-生成器_36

    #生成器函数 def generator(): print(1) return 'a' ret = generator() print(ret) #只要含有yield关键字的函数都是生成器函数 # y ...

  4. Tarjan算法(缩点)

    因为最近在学2sat,需要学习前置技能—Tarjan算法,所以花了一天的时间学习这个算法 算法步骤: 1.从一个点开始dfs,并加入栈 2.如果下一个点没有到过,跳到第一步 3.如果下一个点到过,并且 ...

  5. 转:Linux(Centos)之安装Nginx及注意事项

    1.Nginx的简单说明 a.  Nginx是一个高性能的HTTP和反向代理服务器,也是一个IMAP/POP3/SMTP服务器,期初开发的目的就是为了代理电子邮件服务器室友:Igor Sysoev开发 ...

  6. virtualization - Ubuntu Budgie screen distortion in Hyper-V - Ask Ubuntu

    virtualization - Ubuntu Budgie screen distortion in Hyper-V - Ask Ubuntuhttps://askubuntu.com/questi ...

  7. vue传参二

    <template> <ul> <li v-for="(value,key,index) in list" :key="index" ...

  8. C#实现,C++实现,JS实现 阿拉伯数字金额转换为中文大写金额

    推荐在线编译器  ideone 1. C#实现 :带有负数处理 //把数字金额转换成中文大写数字的函数 //带有负值处理 function changeNumMoneyToChinese(money) ...

  9. day 7-14 数据库完整性约束

    一. 介绍 约束条件与数据类型的宽度一样,都是可选参数 作用:用于保证数据的完整性和一致性 主要分为: PRIMARY KEY 标示该字段为表的主键,可以唯一的标示记录 FOREIGN KEY 标示该 ...

  10. K3BOM跳层

    A自制件,B自制件,C外购件 ,结构为A-B-C 如果需要跳层,则设置A-B跳层,B-C跳层,则生成A计划订单,C计划订单, 假设单独A-B跳层,则MRP运算出的结果也是A计划订单,B计划订单,C计划 ...