[关闭]
@rebirth1120 2019-11-13T09:36:32.000000Z 字数 2777 阅读 683

luoguP1081 开车旅行 解题报告

解题报告


luoguP1081 开车旅行

题意

个城市 , 呈东西方向一字排开, 城市 的海拔为 , , 两个城市 之间的距离为 .

两人开车旅行, 从西向东行驶, 每天都能且只能沿着正方向从一个城市到达另一个城市, 第一天 开车, 之后他们每天交替开车.
的驾驶风格为每次开到离当前城市第二近的城市,
的驾驶风格为每次开到离当前城市最近的城市.

有两个问题 :
1. 给定 , 求在行驶总距离不超过 的条件下, 从哪个城市出发, 能使得 驾驶的距离 与 驾驶的距离 之比最小.
2. 给定 , 分别代表出发的城市和行驶的最大距离, 求 各自的驾驶距离.

思路

其实想到倍增的话这道题就不怎么难了 (然而我是听别人说了这道题是倍增之后再去做的....)

由于从每个城市出发, 下一次到达的城市以及经过的距离是一定的, 所以可以先预处理出每座城市往后的最近城市和次近城市,
然后再预处理出 , 分别表示从点 出发, 经过 座城市后到达的城市, 的行驶距离, 的行驶距离.

最近城市和次进城市我是用 set 来处理, 然后因为 STL 运用不熟练, 还调了一段时间...

总的来说这道题还算简单, 就是预处理时有一些细节还是要注意的.

代码

  1. #include<bits/stdc++.h>
  2. #define ll long long
  3. #define itr iterator
  4. #define lb lower_bound
  5. using namespace std;
  6. const int N=1e5+7;
  7. const int L=20;
  8. const ll inf=1e17;
  9. int n,m,f[N][3],g[N][L+7];
  10. ll h[N],s1[N][L+7],s2[N][L+7];
  11. struct city{
  12. int id;
  13. ll h;
  14. bool operator < (const city x) const{ return h<x.h; }
  15. bool operator <= (const city x) const{ return h<=x.h; }
  16. bool operator > (const city x) const{ return h>x.h; }
  17. bool operator >= (const city x) const{ return h>=x.h; }
  18. bool operator == (const city x) const{ return h==x.h; }
  19. }a[N],fs[4];
  20. set<city> S;
  21. int now;
  22. bool rule(city x,city y){
  23. ll tx=abs(x.h-a[now].h),ty=abs(y.h-a[now].h);
  24. return tx==ty ?x.h<y.h :tx<ty;
  25. }
  26. ll dis(int x,int y){
  27. if(x==0||y==0) return 0;
  28. return abs(h[x]-h[y]);
  29. }
  30. bool clsr(city a,city b,city x){
  31. ll ta=abs(a.h-x.h),tb=abs(b.h-x.h);
  32. if(ta==tb) return a.h<b.h;
  33. else return ta<tb;
  34. }
  35. void pre(){
  36. S.insert(a[n]);
  37. // 各种丑陋的分类讨论...
  38. for(int i=n-1;i>=1;i--){
  39. now=i;
  40. set<city>::itr it=S.lb(a[i]),it1,it2,it3;
  41. if(it!=S.begin()){ it--; it1=it; it++; }
  42. else it1=it;
  43. if(it1!=S.begin()){ it1--; it3=it1; it1++; }
  44. else it3=it1;
  45. if(it!=S.end()){ it++; it2=it; it--; }
  46. else{ it2=it=it1; }
  47. if(it2==S.end()) it2--;
  48. fs[1]=*it1; fs[2]=*it; fs[3]=*it2;
  49. city t3=*it3,t2=*it2;
  50. if(it3!=it1&&clsr(t3,t2,a[i])) fs[3]=*it3;
  51. sort(fs+1,fs+4,rule);
  52. if(fs[1]==fs[2]){
  53. if(fs[1]==fs[3]) f[i][1]=0;
  54. else f[i][1]=fs[3].id;
  55. }
  56. else f[i][1]=fs[2].id;
  57. f[i][2]=fs[1].id;
  58. S.insert(a[i]);
  59. }
  60. for(int i=n;i>=1;i--){
  61. g[i][0]=f[i][1];
  62. s1[i][0]=dis(i,f[i][1]);
  63. g[i][1]=f[f[i][1]][2];
  64. s1[i][1]=dis(i,f[i][1]);
  65. s2[i][1]=dis(f[i][1],g[i][1]);
  66. for(int k=2;k<=L;k++){
  67. g[i][k]=g[g[i][k-1]][k-1];
  68. s1[i][k]=s1[i][k-1]+s1[g[i][k-1]][k-1];
  69. s2[i][k]=s2[i][k-1]+s2[g[i][k-1]][k-1];
  70. }
  71. }
  72. }
  73. void find(int s,ll x,ll &t1,ll &t2){
  74. t1=t2=0;
  75. for(int i=L;i>=0;i--)
  76. if(g[s][i]&&s1[s][i]+s2[s][i]<=x){
  77. x-=s1[s][i]+s2[s][i];
  78. t1+=s1[s][i];
  79. t2+=s2[s][i];
  80. s=g[s][i];
  81. }
  82. }
  83. int run(ll x0){
  84. int ans=0; h[0]=-inf;
  85. ll res1=0,res2=0,t1=0,t2=0;
  86. for(int i=1;i<=n;i++){
  87. find(i,x0,t1,t2);
  88. if(!t2&&res2) continue;
  89. if(res1*t2>t1*res2||(res1*t2==t1*res2&&h[i]>h[ans])){
  90. ans=i;
  91. res1=t1; res2=t2;
  92. }
  93. }
  94. return ans;
  95. }
  96. int main(){
  97. // freopen("drive1.in","r",stdin);
  98. // freopen("drive.out","w",stdout);
  99. cin>>n;
  100. for(int i=1;i<=n;i++){
  101. scanf("%lld",&h[i]);
  102. a[i].id=i; a[i].h=h[i];
  103. }
  104. pre();
  105. ll x0; scanf("%lld",&x0);
  106. printf("%d\n",run(x0));
  107. cin>>m; int s; ll x,t1,t2;
  108. for(int i=1;i<=m;i++){
  109. scanf("%d%lld",&s,&x);
  110. find(s,x,t1,t2);
  111. printf("%lld %lld\n",t1,t2);
  112. }
  113. return 0;
  114. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注