感觉今天被这题虐的脑细胞都没了。。。题解打了一半就不想想下去了。。。
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.