CF639E Bear and Paradox 题解
题意
- 有 个问题,第 个问题的初始得分为 ,所花费的时间为 。
- 设 ,你可以按照某个顺序恰好花费 时间完成所有问题。
- 若你在时刻 完成了问题 ,你可以得到 的得分,其中 是一个 的实数。
- 对于每个 ,都存在至少一个可以使得分最大的最佳做题顺序。
- 对于一个做题顺序,若出现了两个问题 满足 但 的得分严格大于 的得分,则认为这种做题顺序存在悖论。
- 你需要求出最大的 ,使得这个 对应的任意最佳做题顺序都不存在悖论。
- ,,答案精度误差 。
题解
最佳做题顺序一定是按照 从大到小排序的,在所有 都不相同的情况下,设排序后第 个问题的得分为 ,即有 个关于 的一次函数。
题目要求不存在悖论,等价于最大的 满足这 个一次函数在 中不存在交点。
找到对于每个相同的 最靠上和最靠下的一次函数,解出相邻两个 对应的函数交点,取最小的横坐标即可。
当有 相同的时候,会出现有多个最佳做题顺序,因此需要找到每道题对应的一次函数的斜率的最大和最小值。
时间复杂度 。
代码
const int N = 1.5e5 + 7;
const ld eps = 1e-10L;
int n;
ll T, s;
struct P {
int p, t;
ld x, l, r;
inline bool operator < (const P &o) const { return x > o.x; }
} p[N];
int main() {
rd(n);
for (int i = 1; i <= n; i++) rd(p[i].p);
for (int i = 1; i <= n; i++)
rd(p[i].t), p[i].x = 1.0L * p[i].p / p[i].t, T += p[i].t;
sort(p + 1, p + n + 1);
for (int i = 1, j = 0; i <= n; i = j + 1) {
while (j + 1 <= n && abs(p[i].x - p[j+1].x) < eps) ++j;
for (int k = i; k <= j; k++) p[k].l = 1.0L * p[k].p * (s + p[k].t) / T;
for (int k = i; k <= j; k++) s += p[k].t;
for (int k = i; k <= j; k++) p[k].r = 1.0L * p[k].p * s / T;
}
sort(p + 1, p + n + 1, [&](P x, P y) { return x.p < y.p; });
ld ans = 1;
for (int i = 1; i < n; i++)
if (p[i].p < p[i+1].p) {
ld l = 1e8L, r = 0.0L;
int j = i;
while (j && p[j].p == p[i].p) l = min(l, p[j--].l);
j = i + 1;
while (j <= n && p[j].p == p[i+1].p) r = max(r, p[j++].r);
if (l + eps < r) ans = min(ans, (p[i].p - p[i+1].p) / (l - r));
}
printf("%.10Lf\n", ans);
return 0;
}
评论
暂无已公开评论。