NOIP 2012 开车旅行

感觉今天被这题虐的脑细胞都没了。。。题解打了一半就不想想下去了。。。

NOIP 2012 开车旅行
这个题目主要就是求两个问题:①求从哪个城市开始,小A和小B所开路程的比值最小。②求从给定城市出发,小A和小B各自走的路程。
首先把城市的高度拿去排序,放到链表中。再分别找到离他最近和次近的城市,记录下来。
再来就是倍增了
因为它数据的原因,我们的j最多开到17就好了(这句废话)
倍增主要书处理每个点向前走2^j步能到的城市和到这个城市A,B需要走的距离
再来说方程吧:f[I,j]=f[f[I,j-1],j-1]];
a[I,j]=a[I,j-1]+a[f[I,j-1],j-1];
b[I,j]=b[I,j-1]+b[f[I,j-1],j-1]
算出来这些,题目要求的两个问题就好解决了。
介于语言表达问题,先来看程序。。。。。。。。。

  1 label 1;
  2 type point=^rec;
  3      rec=record
  4      z:longint;
  5      q,h:point;
  6 end;
  7 var i,n,m,t,s,top,j,k,ans,dk,lj:longint;
  8     h,a,mi,mmi,b:array[0..100000] of int64;
  9     XXX:array[0..100000] of point;
 10     fa,na,nb:array[0..100000,-2..17] of int64;
 11     p,q:point;
 12     bo:array[0..100000] of boolean;
 13     re:real;
 14     la,lb,x:int64;
 15     flag:boolean;
 16 procedure qsort(l,r:longint);
 17       var i,j,x,y:longint;
 18 begin
 19   x:=h[(l+r) div 2]; i:=l; j:=r;
 20   repeat
 21     while h[i]<x do inc(i);
 22     while x<h[j] do dec(j);
 23     if not (i>j) then
 24      begin
 25       y:=h[i]; h[i]:=h[j]; h[j]:=y;  y:=a[i]; a[i]:=a[j];  a[j]:=y;
 26       inc(i);  dec(j);
 27      end;
 28   until i>j;
 29   if l<j then sort(l,j);
 30   if i<r then sort(i,r);
 31 end;
 32 procedure deal;
 33 begin
 34   la:=0; lb:=0; k:=s; flag:=true;
 35   while flag do
 36    begin
 37     j:=0;
 38     while (x>=la+lb+na[k,j]+nb[k,j])and(fa[k,j]<>0) do inc(j);
 39     if (x<la+lb+na[k,j]+nb[k,j])and(j=0) then flag:=false;
 40     if fa[k,0]=0 then flag:=false;
 41     la:=la+na[k,j-1];
 42     lb:=lb+nb[k,j-1];
 43     k:=fa[k,j-1];
 44    end;
 45   if (mmi[k]<>0)and(la+lb+abs(b[mmi[k]]-b[k])<=x) then
 46    la:=la+abs(b[mmi[k]]-b[k]);
 47 end;
 48 begin
 49   assign(input,'drive.in'); reset(input);
 50   assign(output,'drive.out'); rewrite(output);
 51   readln(n);  //读入
 52   for i:=1 to n do
 53    begin   
 54     read(h[i]);  
 55     a[i]:=i;  //记录每个点的位置
 56     b[i]:=h[i];
 57    end;
 58   qsort(1,n);  //递增的快排
 59   new(XXX[a[1]]); 
 60   XXX[a[1]]^.q:=nil; 
 61   XXX[a[1]]^.z:=a[1]; 
 62   for i:=2 to n do
 63    begin
 64     new(XXX[a[i]]);
 65     XXX[a[i]]^.q:=XXX[a[i-1]];   //^.q表示前面一个指针
 66     XXX[a[i]]^.z:=a[i];           //^.z表示这个指针是哪个数
 67     XXX[a[i-1]]^.h:=XXX[a[i]];  // ^.h表示后面一个指针   
 68    end;
 69   XXX[a[n]]^.h:=nil;
 70   for i:=1 to n do
 71    begin
 72     p:=XXX[i]^.q;  //为了方便,把它前面的指针赋值给p
 73     q:=XXX[i]^.h;  //为了方便,把它后面的指针赋值给p 
 74     if (p=nil)and(q=nil) then goto 1; //goto 不懂可以百度
 75     if (q<>nil)and((p=nil)or(b[i]-b[p^.z]>b[q^.z]-b[i])) then  //方便找最近的
 76      begin                                                    
 77       mi[i]:=q^.z;  //记录这个点
 78       q:=q^.h;        
 79       if (p=nil)and(q=nil) then goto 1;  
 80       if (q<>nil)and((p=nil)or(b[i]-b[p^.z]>b[q^.z]-b[i])) then mmi[i]:=q^.z else mmi[i]:=p^.z;
 81      end
 82     else 
 83      begin  //方便找次近的
 84       mi[i]:=p^.z;  
 85       p:=p^.q;
 86       if (p=nil)and(q=nil) then goto 1;
 87       if (p<>nil)and((q=nil)or(b[q^.z]-b[i]>=b[i]-b[p^.z])) then
 88        mmi[i]:=p^.z else mmi[i]:=q^.z;
 89      end;
 90 1:  if XXX[i]^.q<>nil then XXX[i]^.q^.h:=XXX[i]^.h;    
 91     if XXX[i]^.h<>nil then XXX[i]^.h^.q:=XXX[i]^.q;    
 92     XXX[i]:=nil; //最后要记得把这个指针记空
 93    end;
 94   for i:=1 to n do if mmi[i]<>0 then       
 95    begin
 96     t:=mmi[i];
 97     if mi[t]<>0 then
 98      begin
 99       nb[i,0]:=abs(b[t]-b[mi[t]]);
100       na[i,0]:=abs(b[i]-b[t]);
101      end;
102    fa[i,0]:=mi[t];
103    end;
104    for i:=1 to n do fa[i,-1]:=i;
105    for j:=1 to 17 do
106     for i:=1 to n do
107      begin
108       fa[i,j]:=fa[fa[i,j-1],j-1];
109       if fa[i,j]<>0 then
110        begin
111         na[i,j]:=na[i,j-1]+na[fa[i,j-1],j-1];
112         nb[i,j]:=nb[i,j-1]+nb[fa[i,j-1],j-1];
113        end;
114      end;
115   read(x);
116   re:=10000000000;
117   for s:=1 to n do
118    begin
119     deal;
120     if (lb<>0)and(re>la/lb) then
121      begin
122       re:=la/lb;
123       ans:=s;
124      end;
125    end;
126   writeln(ans);
127   read(m);
128   for i:=1 to m do
129    begin
130     read(s,x);  //依据s,x判断能走到哪个城市及A,B走过距离
131     deal;
132     writeln(la,' ',lb);
133    end;
134   close(input); close(output);
135 end.
View Code
原文地址:https://www.cnblogs.com/oxxxo/p/3374314.html