Listing WTELL.PAS
Program Tell;
{$B-,F+,I-,N+,R-,S-}
Const NMax=3000;
Type PointType=record X,Y:Extended end;
PointVector=array[-1..NMax]of PointType;
BoolFunc=Function(i,j:Integer):Boolean;
Var P:PointVector;
N,M,NSecants,IndMinX,IndMaxX:Integer;
{ Indicii punctelor extreme pe X }
A,B,C,SumDist:Extended;
Better:BoolFunc; { Criteriul folosit }
{ la maximizare (Greater/Less) }
Procedure ReadPoints;
{ Citeste punctele si calculeaza }
{ indicii minimului & maximului pe X }
Var i:Integer;
begin
Readln(N); IndMinX:=0; IndMaxX:=0;
for i:=0 to N-1 do
with P[i] do
begin
Readln(X,Y);
if X<P[IndMinX].X then IndMinX:=i;
if X>P[IndMaxX].X then IndMaxX:=i
end;
NSecants:=0; SumDist:=0
end;
Function Dist(i:Integer):Extended;
{ Distanta de la un punct }
{ la o dreapta (normalizata) }
begin
Dist:=A*P[i].X+B*P[i].Y+C
end;
Function Greater(i,j:Integer):Boolean;
{ Arata daca P[i] este "mai mare" }
{ ca P[j] relativ la directia dreptei }
begin
Greater:=(Dist(i)>=Dist(j))
end;
Function Less(i,j:Integer):Boolean;
{ Arata daca P[i] este "mai mic" }
{ ca P[j] relativ la directia dreptei }
begin
Less:=(Dist(i)<=Dist(j))
end;
Function FindBest(Lo,Hi:Integer;
Better:BoolFunc):Integer;
{ Intoarce indicele punctului optim pe }
{ directia vectorului de componente A si B.}
{ "Optim" inseamna fie "maxim", fie "minim"}
{ dupa cum Better este Greater sau Less }
{ (criteriul de comparatie) }
Var Mid:Integer;
Finished:Boolean;
begin
Finished:=False;
while((Hi+N-Lo) mod N>1) and not Finished do
begin
if Hi>Lo
then Mid:=(Lo+Hi) div 2
else Mid:=((Lo+Hi+N) div 2) mod N;
if Better(Mid,(Mid+1) mod N)
then Hi:=Mid
else
if Better(Mid,(Mid+N-1) mod N)
then Lo:=Mid
else Finished:=True
end;
if Better(Hi,Lo) then FindBest:=Hi
else FindBest:=Lo
end;
Procedure CountDistance(Min,Max:Integer);
{ Vede daca minimul si maximul gasite dupa }
{ directia ceruta sunt: }
{ a) De parti diferite ale dreptei -> }
{ dreapta e secanta, distanta e zero }
{ b) De aceeasi parte, distanta este a }
{ celui mai apropiat dintre ele }
Var DMin, DMax:Extended;
begin
DMin:=Dist(Min);
DMax:=Dist(Max);
if DMin*DMax<=0
then Inc(NSecants)
else
if Abs(DMin)<Abs(DMax)
then SumDist:=SumDist+Abs(DMin)
else SumDist:=SumDist+Abs(Dmax)
end;
Procedure CheckLines;
Var i:Integer;
Max,Min,Candidate:Integer;
D:Extended;
begin
Readln(M);
for i:=1 to M do
begin
Readln(A,B,C);
{ Normalizam ecuatia dreptei }
D:=Sqrt(A*A+B*B);
A:=A/D;
B:=B/D;
C:=C/D;
{ Cautam punctul MAXIM dupa directia }
{ data, pe ambele lanturi }
Max:=FindBest(IndMinX,IndMaxX,Greater);
Candidate:=FindBest(IndMaxX,IndMinX,Greater);
if Greater(Candidate,Max)
then Max:=Candidate;
{ Cautam punctul MAXIM dupa directia }
{ data, pe ambele lanturi }
Min:=FindBest(IndMinX,IndMaxX,Less);
Candidate:=FindBest(IndMaxX,IndMinX,Less);
if Less(Candidate,Min)
then Min:=Candidate;
CountDistance(Min,Max)
end
end;
Begin
Assign(Input,'TELL.IN');
Reset(Input);
Assign(Output,'TELL.OUT');
Rewrite(Output);
ReadPoints;
CheckLines;
Writeln(NSecants);
Writeln(SumDist:0:2);
Close(Input);
Close(Output)
End.