题解 CF639E 【Bear and Paradox】
标签: 贪心, 二分答案.
Part 1
首先我们需要知道一个最优顺序有什么样的性质.
实际上是按
我们交换这两道题的顺序, 其他题目得分显然不发生变化, 而这两题的得分变为
Part 2
有了 Part 1 的结论后, 我们就可以处理出每个问题的最早完成时间和最晚完成时间. 然后二分一个
时间复杂度
#include <bits/stdc++.h>
using namespace std;
int read();
int n;
int st[200005], top;
long long T;
struct P {
long long p, t, tmin, tmax, sum;
int fp;
} p[200005];
bool cmppdivt(P a, P b) { return a.p * b.t > b.p * a.t; }
bool cmpp(P a, P b) { return a.p < b.p; }
bool check(double x) {
double mx = 0, tmx = 0;
for (int i = 1; i <= n; ++i) {
if (p[i].p != p[i - 1].p) mx = tmx;
if ((1 - x * p[i].tmax / T) * p[i].p < mx) return 0;
tmx = max(tmx, (1 - x * p[i].tmin / T) * p[i].p);
}
return 1;
}
int main() {
n = read();
for (int i = 1; i <= n; ++i) st[i] = p[i].p = read();
for (int i = 1; i <= n; ++i) T += (p[i].t = read());
sort(st + 1, st + 1 + n), top = unique(st + 1, st + 1 + n) - st - 1;
for (int i = 1; i <= n; ++i)
p[i].fp = lower_bound(st + 1, st + top + 1, p[i].p) - st;
sort(p + 1, p + 1 + n, cmppdivt);
for (int i = 1; i <= n; ++i) p[i].sum = p[i - 1].sum + p[i].t;
for (int i = 1, j; i <= n; i = j + 1) {
j = i;
while (j < n && p[j + 1].p * p[i].t == p[i].p * p[j + 1].t) ++j;
for (int k = i; k <= j; ++k)
p[k].tmin = p[i - 1].sum + p[k].t, p[k].tmax = p[j].sum;
}
sort(p + 1, p + 1 + n, cmpp);
double l = 0, r = 1, mid;
while (r - l > 1e-6) check(mid = (l + r) / 2) ? l = mid : r = mid;
printf("%.8lf", l);
return 0;
}
const int _SIZE = 1 << 22;
char ibuf[_SIZE], *iS = ibuf, *iT = ibuf;
#define gc \
(iS == iT ? iT = ((iS = ibuf) + fread(ibuf, 1, _SIZE, stdin)), \
(iS == iT ? EOF : *iS++) : *iS++)
int read() {
int x = 0, f = 1;
char c = gc;
while (!isdigit(c)) f = (c == '-') ? -1 : f, c = gc;
while (isdigit(c)) x = x * 10 + c - '0', c = gc;
return x * f;
}