pretty_good_pro
% pretty_good_pro.pi (in Picat)
% by N.F. Zhou, Nov. 28, 2015
% https://code.google.com/codejam/contest/5224486/dashboard#s=p2
% Problem C. Pretty Good Proportion
% World Finals 2015
% to use: picat pretty_good_pro < input_file > output_file
%
/*
Input: S is the input sequence of 0s and 1s.
N is the size of S.
F is the given fraction.
Let Ci be the number of 1s from S1 to Si (1-based index). Assume
the substring Si..Sj has the closest 1-proportion:
(Cj - C(i-1)) / (j-i+1) .=. F (.=. means close-to, C0 is 0)
Then
Cj - F*j .=. C(i-1) - F*(i-1)
In order to avoid floating-point operations, change the equation to:
1000000*Cj - 1000000*F*j .=. 1000000*C(i-1) - 1000000*F*(i-1)
Let Di be 1000000*Ci - 1000000*F*i.
This algorithm constructs a list, [(0,0),(D1,1),(D2,2),...,(Dn,n)], and sort it.
Then it compares the neighboring pairs in the sorted list to find the pair
(Di,i) and (Dj,j) such that abs((Cj-Ci)/(j-i)-F) is the minimum.
*/
import util.
main =>
T = to_integer(read_line()),
foreach (CN in 1..T)
[S1,S2] = read_line().split(),
N = to_integer(S1),
F = to_integer(to_real(S2)*1000000),
S = read_line().to_array(),
do_case(CN,S,N,F)
end.
do_case(CN,S,N,F) =>
C = new_array(N),
Acc = 0,
foreach (I in 1..N)
Acc := cond(S[I]=='1', Acc+1, Acc),
C[I] = Acc
end,
Ds = [(C[I]*1000000 - I*F, I) : I in 1..N],
SDs = sort([(0,0)|Ds]),
find_i(SDs,C,F/1000000.0,Start),
printf("Case #%w: %w\n",CN, Start).
find_i([(_,I)|SDs@[(_,J)|_]],C,F,Start) =>
comp_diff(I,J,C,F,Diff),
find_i(SDs,C,F,min(I,J),Start,Diff).
find_i([_],_C,_F,Start0,Start,_Diff) =>
Start = Start0.
find_i([(_,I)|SDs@[(_,J)|_]],C,F,Start0,Start,Diff) =>
comp_diff(I,J,C,F,Diff1),
(Diff1 < Diff ->
find_i(SDs,C,F,min(I,J),Start,Diff1)
; Diff1==Diff ->
find_i(SDs,C,F,min(min(I,J),Start0),Start,Diff)
;
find_i(SDs,C,F,Start0,Start,Diff)
).
comp_diff(I,J,C,F,Diff),I>J =>
comp_diff(J,I,C,F,Diff).
comp_diff(0,J,C,F,Diff) =>
Diff = abs((C[J]-0)/J-F).
comp_diff(I,J,C,F,Diff) =>
Diff = abs((C[J]-C[I])/(J-I)-F).