题意

城市\(i\)的海拔高度为\(H_i\)(各不相同)。定义距离为海拔差的绝对值

小\(A\)和小\(B\)轮流开车。从\(S\)起,一直向东行驶。

小\(A\)会选择第二近的城市作为目的地。小\(B\)选择一个最近的城市作为目的地。(如果当前城市到两个城市的距离相同,则认为离海拔低的那个城市更近)。如果无法再开了,或者到达目的地会使行驶的总距离超出\(X\)公里,他们就会结束旅行。

单次询问:给定\(X\),问从哪个城市出发,小\(A\)行的路程与小\(B\)行的路程的比值最小

多次询问:给定\(S\)和\(X\),问小\(A\)行的路程与小\(B\)行的路程

\(1 \leq N \leq 10^5,1 \leq M \leq 10^5\)

思路

首先肯定要解决一个问题,小\(A\)和小\(B\)的目的地在哪里。

先排序,然后从第一个城市开始,比较\(i-1,i-2,i+1,i+2\)处距离。

很显然,由于是第一个点,这个时候找到的任何点一定在它东边。

同样的,找完第一个点后将第一个点删除,那么第二个点自然成为了第一个点,依次下去,便在\(O(n)\)的复杂度内完成了预处理。

接下来,就可以想到用倍增来解决。

用\(f[i][j]\)表示从\(j\)出发第\(2^i\)天到达的城市,发现除了\(i=0\)时是\(A\)在开其他都是\(B\)开,所以转移就很简单了\(f[i][j]=f[i-1][f[i-1][j]];\)

那么求出了路径,距离只要减一减就好了。

用\(g[i][j][0]\)表示从\(j\)出发第\(2^i\)天\(A\)开的,用\(g[i][j][1]\)表示从\(j\)出发第\(2^i\)天\(B\)开的,转移:

\(g[i][j][0]=g[i-1][j][0]+g[i-1][f[i-1][j]][0];\)

\(g[i][j][1]=g[i-1][j][1]+g[i-1][f[i-1][j]][1];\)

接下来的询问只要每次倍增凑距离就好了

对于第一个询问枚举出发点再比较

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

  1. #include <bits/stdc++.h>
  2. const int N=100005;
  3. double INF=1000000000;
  4. using std::sort;
  5. int a[N],b[N],Next[N],last[N],c[N],n,m,f[21][N],x,ans=0,s;
  6. long long h[N],suma,sumb,g[21][N][2];
  7. bool cmp(int x,int y){
  8. return h[x]<h[y];
  9. }
  10. int d(int x,int y){
  11. return abs(h[x]-h[y]);
  12. }
  13. void solve(int x,int s){
  14. for (int i=20;i>=0;i--)
  15. if (g[i][s][0]+g[i][s][1]<=1ll*x){
  16. x-=g[i][s][0]+g[i][s][1];
  17. suma+=g[i][s][0];
  18. sumb+=g[i][s][1];
  19. if (s==f[i][s]) return;
  20. s=f[i][s];
  21. }
  22. }
  23. int main(){
  24. scanf("%d",&n);
  25. for (int i=1;i<=n;i++) scanf("%lld",&h[i]),c[i]=i;
  26. h[0]=-200000000000;
  27. sort(c+1,c+n+1,cmp);
  28. for (int i=1;i<=n;i++) last[c[i]]=c[i-1],Next[c[i]]=c[i+1];
  29. for (int i=1;i<=n;i++){
  30. int x1=last[i],x2=last[x1],x3=Next[i],x4=Next[x3];
  31. int dis1=abs(h[i]-h[x1]),dis2=abs(h[i]-h[x2]),dis3=abs(h[i]-h[x3]),dis4=abs(h[i]-h[x4]);
  32. if (dis1<dis3 ||(dis1==dis3 && h[x1]<h[x3])) b[i]=x1; else b[i]=x3;
  33. if (dis2<dis3 ||(dis2==dis3 && h[x2]<h[x3])) a[i]=x2;
  34. else if (dis4<dis1 ||(dis4==dis1 && h[x4]<h[x1])) a[i]=x4;
  35. else if (dis1<dis3 ||(dis1==dis3 && h[x1]<h[x3])) a[i]=x3;
  36. else a[i]=x1;
  37. if (a[i]==0) a[i]=i;
  38. if (b[i]==0) b[i]=i;
  39. last[Next[i]]=last[i],Next[last[i]]=Next[i];
  40. }
  41. for (int i=1;i<=n;i++){
  42. f[0][i]=a[i];if (a[i]!=i) f[1][i]=b[a[i]];else f[1][i]=i;
  43. g[0][i][0]=d(i,f[0][i]),g[1][i][0]=g[0][i][0];
  44. if (a[i]!=i)g[1][i][1]=d(a[i],b[a[i]]);
  45. }
  46. for (int i=2;i<=20;i++)
  47. for (int j=1;j<=n;j++){
  48. f[i][j]=f[i-1][f[i-1][j]];
  49. g[i][j][0]=g[i-1][j][0]+g[i-1][f[i-1][j]][0];
  50. g[i][j][1]=g[i-1][j][1]+g[i-1][f[i-1][j]][1];
  51. }
  52. scanf("%d",&x);
  53. double now=INF;
  54. for (int i=1;i<=n-2;i++){
  55. suma=0,sumb=0;
  56. solve(x,i);
  57. if (now==INF && sumb==0 && h[i]>h[ans]) ans=i;
  58. if (sumb==0) continue;
  59. if (suma*1.0/sumb<now ||(suma*1.0/sumb==now && h[i]>h[ans])){
  60. now=suma*1.0/sumb;
  61. ans=i;
  62. }
  63. }
  64. printf("%d\n",ans);
  65. scanf("%d",&m);
  66. for (int i=1;i<=m;i++){
  67. scanf("%d%d",&s,&x);
  68. suma=0,sumb=0;
  69. solve(x,s);
  70. printf("%lld %lld\n",suma,sumb);
  71. }
  72. }

后记

要注意\(h[0]\)的初始化,原来没仔细看数据结果爆了\(4\)发

LG1081 开车旅行的更多相关文章

  1. Luogu 1081 【NOIP2012】开车旅行 (链表,倍增)

    Luogu 1081 [NOIP2012]开车旅行 (链表,倍增) Description 小A 和小B决定利用假期外出旅行,他们将想去的城市从1到N 编号,且编号较小的城市在编号较大的城市的西边,已 ...

  2. CH5701 开车旅行

    题意 5701 开车旅行 0x50「动态规划」例题 描述 小A和小B决定利用假期外出旅行,他们将想去的城市从1到N编号,且编号较小的城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 ...

  3. 2012Noip提高组Day1 T3 开车旅行

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

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

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

  5. 开车旅行 【NOIP2012 D1T3】

    开车旅行 [NOIP2012 D1T3] 倍增 首先令\(a[i]\)表示从i出发最近的城市下标,\(b[i]\)表示从i出发第二近的城市下标 可以维护一个\(\text{set<pair< ...

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

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

  7. 开车旅行 2012年NOIP全国联赛提高组(倍增+set)

    开车旅行 2012年NOIP全国联赛提高组  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 钻石 Diamond     题目描述 Description 小A 和小B决定利用 ...

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

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

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

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

随机推荐

  1. 【转载】IIS出现“HTTP 错误 500.0,C:\php\php-cgi.exe - FastCGI 进程意外退出”解决方法

    昨天给大家介绍了在windows+iis的平台上搭建支持php+mysql平台的文章,教程步骤都是笔者一步一个操作然后一个记录介绍给大家的,实机演练,教程绝对切实可用,但是不同的同学在不同的环境下按照 ...

  2. Maven全局配置

    Maven的全局配置文件是Maven安装目录conf/settings.xml文件,该文件可以配置仓库.代理.profile.镜像.插件等 <settings> <localRepo ...

  3. vue app混合开发蓝牙串口连接(报错java.io.IOException: read failed, socket might closed or timeout, read ret: -1;at android.bluetooth.BluetoothSocket.connect at js/BluetoothTool.js:329)

    我使用的uni-app <template> <view class="bluetooth"> <!-- 发送数据 --> <view c ...

  4. Object.freeze(); 方法冻结一个对象。

    Object.freeze() 方法可以冻结一个对象.一个被冻结的对象再也不能被修改: 冻结了一个对象则不能向这个对象添加新的属性,不能删除已有属性,不能修改该对象已有属性的可枚举性.可配置性.可写性 ...

  5. java---- XMLEncoder 和 XMLDecoder 和 xSteam工具使用

    XMLEncoder: 将对象写入XML数据中 import org.dom4j.DocumentException; import java.beans.XMLEncoder; import jav ...

  6. Sharding-JDBC

    1.官网文档:https://shardingsphere.apache.org/document/legacy/3.x/document/cn/manual/sharding-jdbc/usage/ ...

  7. Python学习笔记八

    类的高级用法 多态:   在其他语言,使用的是类的继承. 在python中,不需要指定数据类型. 基于TCP协议的socket通信实现: 类似于打电话的情景. 服务端: 1.买手机 2.插卡 3.开机 ...

  8. bat路径中有空格

    例如bat文件中写 C:/Program Files (x86)/Google/Chrome/Application/chrome.exe ./html/index.html pause   会报错, ...

  9. Android+openCV 动态人脸检测

    动态人脸检测前提是需要打开摄像头. 网上看了很多教程,我知道的有两种方式打开摄像头: JavaCameraView mCameraView = new JavaCameraView(this, -1) ...

  10. Linux-vi编辑器简单使用(保证存活)

    vi编辑器基本模式 命令行模式(command mode) 光标移动.复制粘贴.删除 插入模式(insert mode) 文字输入 底行模式(last line mode) 保存.退出 模式转换 co ...