-
Notifications
You must be signed in to change notification settings - Fork 22
/
Copy pathpretty-good-proportion.cpp
127 lines (114 loc) Β· 3.07 KB
/
pretty-good-proportion.cpp
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
// Copyright (c) 2015 kamyu. All rights reserved.
/*
* Google Code Jam 2015 World Finals - Problem C. Pretty Good Proportion
* https://code.google.com/codejam/contest/5224486/dashboard#s=p2
*
* Time: O(NlogN)
* Space: O(N)
*
*/
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <utility>
using std::cin;
using std::cout;
using std::endl;
using std::string;
using std::vector;
using std::pair;
using std::make_pair;
using std::sort;
using std::swap;
using std::abs;
using std::min;
const int PRECISION = 1e6;
int64_t gcd(int64_t x, int64_t y) {
while (y > 0) {
x %= y;
swap(x, y);
}
return x;
}
// No multiplication in comparison of fractions
// to avoid overflow.
bool smaller(int64_t y1, int64_t x1,
int64_t y2, int64_t x2) {
if (y1 / x1 < y2 / x2) {
return true;
} else if (y1 / x1 > y2 / x2) {
return false;
} else {
y1 %= x1, y2 %= x2;
if (y2 == 0) {
return false;
} else if (y1 == 0) {
return true;
} else {
return smaller(x2, y2, x1, y1);
}
}
}
// Find the minimum of |dy/dx - f|
void check(const int64_t F, const vector<int>& sum,
int i, int j,
int64_t *min_x, int64_t *min_y,
int *ans) {
int64_t dx = abs(j - i), dy = abs(sum[j] - sum[i]);
// y / x = |dy/dx - f|
int64_t y = abs(dy * PRECISION - dx * F), x = dx * PRECISION;
int64_t g = gcd(x, y);
x /= g, y /= g; // Avoid overflow.
if (smaller(y, x, *min_y, *min_x)) {
*min_x = x, *min_y = y;
*ans = min(i, j);
} else if (!smaller(*min_y, *min_x, y, x) && min(i, j) < *ans) {
// If they are the same slope,
// update ans to the smallest i.
*ans = min(i, j);
}
}
int pretty_good_proportion() {
int N;
double f;
cin >> N >> f;
int64_t F = static_cast<int64_t>(f * PRECISION);
string s;
cin >> s;
vector<int> sum(N + 1);
for (int i = 0; i < N; ++i) {
sum[i + 1] = sum[i] + ((s[i] == '1') ? 1 : 0);
}
vector<pair<int64_t, int>> p(N + 1);
for (int i = 0; i < N + 1; ++i) {
// Diff error f(i): #(1s) - i * f
p[i] = make_pair(static_cast<int64_t>(sum[i]) * PRECISION -
static_cast<int64_t>(i) * F,
i);
}
// Time: O(nlogn)
// Sort the pair (f(i), i) by diff error f(i)
sort(p.begin(), p.end());
// ans is with the min diff error |dy / dx - f| = min_y / min_x
int64_t min_x = 1, min_y = 1;
int ans = N - 1;
// Try out all neighboring pairs which could form
// the substring with the minima f(i) difference "dy".
// Find the min diff error |dy / dx - f|
// in all neighboring pairs.
for (int i = 0; i < N; ++i) {
check(F, sum, p[i].second, p[i + 1].second,
&min_x, &min_y, &ans);
}
return ans;
}
int main() {
int T;
cin >> T;
for (int test = 1; test <= T; ++test) {
cout << "Case #" << test << ": "
<< pretty_good_proportion() << endl;
}
return 0;
}