要求得到平均产奶量的最小值,想到二分答案。
emm...但是我在如何判断当前 \(mid\) 是否能成立上卡了好久,这里就需要思维了。
还是要想到本质上,可以试着用数学式子表达当前 \(mid\) 的合法条件,
若当前要删除 \([l,r]\) 的数,则有:(这里又可以想到用 前缀和 预处理)
\[\begin{aligned} \frac{S_n - Sr + S_{l-1}}{n-r+(l-1)}&\leqslant mid \\ S_n - Sr + S_{l-1}&\leqslant mid(n-r+l-1) \\ S_n - Sr + S_{l-1} -mid(n-r+l-1)&\leqslant 0 \\ \sum_{i=1}^{m}(a_i - mid)&\leqslant0~~~~~(m\in[1,l-1]\cup[r,n]) \end{aligned}\]到这里应该是最简式子了。
而知道 \(l,r\) 是不定的,应该怎么取?如果这个式子成立,直观上肯定知道不可能所有取值都能满足,
也就是说,$$\exists~l,r\in[2,n-1],l\leqslant r,~~ \sum_{i=1}^{m}(a_i - mid)\leqslant0$$
那不就 一定有 :
\[\Bigg [\sum_{i=1}^{m}(a_i - mid)\Bigg ]_{min}\leqslant0 \]所以 \(l,r\) 只要每次取到最小值,判断所有最小值中只要有一个成立就可取 \(mid\)
因此,思路也就来了,构建新的数组表达 \(a_i - mid\) ,
在此上,由于从中间删除,则需要求一个前缀和一个后缀和,同时分别维护最小值,
最后注意,头和尾不能删,也不能一个都不删。
#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;
}
标签:P2115,sum,db,mid,最小值,USACO14MAR,leqslant0,Sabotage,leqslant
From: https://www.cnblogs.com/hi-zwjoey/p/17783598.html