P2115 [USACO14MAR] Sabotage G(二分/思维)

题目 link

要求得到平均产奶量的最小值,想到二分答案。

emm...但是我在如何判断当前 mid 是否能成立上卡了好久,这里就需要思维了。

还是要想到本质上,可以试着用数学式子表达当前 mid 的合法条件,

若当前要删除 [l,r] 的数,则有:(这里又可以想到用 前缀和 预处理)

SnSr+Sl1nr+(l1)midSnSr+Sl1mid(nr+l1)SnSr+Sl1mid(nr+l1)0i=1m(aimid)0     (m[1,l1][r,n])

到这里应该是最简式子了。

而知道 l,r 是不定的,应该怎么取?如果这个式子成立,直观上肯定知道不可能所有取值都能满足,

也就是说, l,r[2,n1],lr,  i=1m(aimid)0

那不就 一定有 :

[i=1m(aimid)]min0

所以 l,r 只要每次取到最小值,判断所有最小值中只要有一个成立就可取 mid

因此,思路也就来了,构建新的数组表达 aimid

在此上,由于从中间删除,则需要求一个前缀和一个后缀和,同时分别维护最小值,

最后注意,头和尾不能删,也不能一个都不删。

#include <bits/stdc++.h>
#define re register int
#define min(x, y) (x < y ? x : y)
using namespace std;
typedef double db;
const int N = 1e5 + 10;
const db eps = 1e-5, inf = 0x3f3f3f3f;
int n;
db a[N], l, r, b[N], s1[N], s2[N], s1min[N], s2min[N];
bool check(db mid)
{
for (re i = 0; i <= n + 1; i ++)
s1min[i] = inf, s2min[i] = inf;
for (re i = 1; i <= n; i ++) b[i] = a[i] - mid;
for (re i = 1; i <= n; i ++)
{
s1[i] = s1[i - 1] + b[i];
s1min[i] = min(s1min[i - 1], s1[i]);
}
for (re i = n; i ; i --)
{
s2[i] = s2[i + 1] + b[i];
s2min[i] = min(s2min[i + 1], s2[i]);
}
for (re i = 1; i <= n - 2; i ++)
{
if (s1min[i] + s2min[i + 2] <= 0)
return true;
}
return false;
}
void search()
{
l = 1, r = N;
while (l + eps < r)
{
db mid = (l + r) / 2;
if (check(mid)) r = mid;
else l = mid;
}
}
int main()
{
scanf("%d", & n);
for (re i = 1; i <= n; i ++) cin >> a[i];
search();
printf("%.3lf\n", l);
return 0;
}

类似: P1419 寻找段落

posted @   Zhang_Wenjie  阅读(17)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示