-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathPIE.cs
136 lines (115 loc) · 4.39 KB
/
PIE.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
using System;
using System.Linq;
// https://www.spoj.com/problems/PIE/ #binary-search #optimization
// Finds out how much pie each person can get when they all need the same amount.
public static class PIE
{
public static double Solve(int pieCount, int personCount, int[] pieRadii)
{
double[] orderedPieVolumes = pieRadii
// Pies are cylinders of height 1.
.Select(r => Math.PI * r * r * 1)
// Order so that we can speed up the verifier a bit--unrelated to the binary search.
.OrderByDescending(v => v)
.ToArray();
double maxPieVolume = orderedPieVolumes.First();
return BinarySearch.Search(
start: 0.00001,
// Can't combine volume from multiple pies, so this is the max possible slice size.
end: maxPieVolume,
// Epsilon can be as low as 0.0001 to get AC, but this guarantees same output as example.
epsilon: 0.00001,
verifier: sv => CanDistributeSlices(pieCount, personCount, orderedPieVolumes, sv),
mode: BinarySearch.Mode.TrueToFalse) ?? 0;
}
private static bool CanDistributeSlices(
int pieCount, int personCount, double[] orderedPieVolumes, double sliceVolume)
{
int unfedPersonCount = personCount;
for (int p = 0; p < pieCount && unfedPersonCount > 0; ++p)
{
int piesSliceCount = (int)(orderedPieVolumes[p] / sliceVolume);
// The volumes are ordered. If this pie doesn't contribute any slices, no
// future pies will either. Since we haven't fed everyone yet, we never will.
if (piesSliceCount == 0) return false;
unfedPersonCount -= piesSliceCount;
}
return unfedPersonCount <= 0;
}
}
// This facilitates predicate-based binary searching, where the values being searched on
// satisfy the predicate in an ordered manner, in one of two ways:
// [false false false ... false true ... true true true] (true => anything larger is true)
// [true true true ... true false ... false false false] (true => anything smaller is true)
// In the first, the goal of the search is to locate the smallest value satisfying the predicate.
// In the second, the goal of the search is to locate the largest value satisfying the predicate.
// For more info, see: https://www.topcoder.com/community/data-science/data-science-tutorials/binary-search/.
public static class BinarySearch
{
public enum Mode
{
FalseToTrue,
TrueToFalse
};
public static double? Search(
double start, double end, double epsilon, Predicate<double> verifier, Mode mode)
=> mode == Mode.FalseToTrue
? SearchFalseToTrue(start, end, epsilon, verifier)
: SearchTrueToFalse(start, end, epsilon, verifier);
private static double? SearchFalseToTrue(
double start, double end, double epsilon, Predicate<double> verifier)
{
if (start > end) return null;
double mid;
while (end - start > epsilon)
{
mid = start + (end - start) / 2;
if (verifier(mid))
{
end = mid;
}
else
{
start = mid + epsilon / 2;
}
}
return verifier(start) ? start : (double?)null;
}
private static double? SearchTrueToFalse(
double start, double end, double epsilon, Predicate<double> verifier)
{
if (start > end) return null;
double mid;
while (end - start > epsilon)
{
mid = start + (end - start) / 2;
if (verifier(mid))
{
start = mid;
}
else
{
end = mid - epsilon / 2;
}
}
return verifier(start) ? start : (double?)null;
}
}
public static class Program
{
private static void Main()
{
int remainingTestCases = int.Parse(Console.ReadLine());
while (remainingTestCases-- > 0)
{
string[] line = Console.ReadLine().Split();
int pieCount = int.Parse(line[0]);
int friendCount = int.Parse(line[1]);
int[] pieRadii = Array.ConvertAll(
Console.ReadLine().Trim().Split(),
int.Parse);
Console.WriteLine(
PIE.Solve(pieCount, friendCount + 1, pieRadii).ToString("F4"));
}
}
}