首页 > 其他 > 详细

「USACO14MAR」破坏Sabotage

时间:2020-02-04 20:56:10      阅读:80      评论:0      收藏:0      [点我收藏+]

给出一段区间 \(w[1...n]\),要求去掉其中一段子区间使得区间剩下部分平均值最大,且不能去掉头和尾,去掉的区间长度 \(len\ge1\) 。其中 \(3\le n\le 10^5\)

Luogu

分析

0/1 分数规划问题。

因为一段区间的平均值为 \(\frac{\sum_{d=i}^jw[d]}{j-i+1}\) ,所以我们可以用前缀和的思想,设 s[i] 为前 \(i\) 项的和。

假设要去掉区间为 \(i\)\(j(i<j)\) ,剩下的区间的平均值为 \(t\),则有

\[s[n]-s[j]+s[i-1]=t(n-j+i-1)\]

移项得

\[s[n]-t*n-(s[j]-t*j-s[i-1]+t*(i-1))=0\]

于是我们设 \(d[i]=s[i]-t*i\)

\[d[n]-(d[j]-d[i-1])=0\]

易知,当 \(d[n]>d[j]-d[i-1]\) 时,一定有比 \(t\) 更好的答案,当 \(d[n]=d[j]-d[i-1]\) 时, \(t\) 就是最优解,所以我们可以用二分来逐渐逼近最优解,找到答案。

于是我们只需找到 \(max(d[j]-d[i-1])\) ,判断其是否小于 \(d[n]\) 即可,但由于直接找 \(max(d[j])\)\(min(d[i-1])\) 不好使 \(i<j\) ,所以我们用 mx[]mn[] 来记录最大与最小值,显而易见,若 \(max(d[j]-d[i-1])\le d[n]\) ,则每一对 \(d[j]-d[i-1]\) 一定小于等于 \(d[n]\) ,故我们每次判断 \(mx[i]-mn[i-1]\) 是否小于等于 \(d[n]\) 就好了。

代码

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define eps 1e-7
#define N 100003
#define il inline
#define re register
#define INF 0x3f3f3f3f
#define tie0 cin.tie(0),cout.tie(0)
#define fastio ios::sync_with_stdio(false)
#define File(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout)
using namespace std;
typedef long long ll;
typedef double db;

template <typename T> inline void read(T &x) {
    T f = 1; x = 0; char c;
    for (c = getchar(); !isdigit(c); c = getchar()) if (c == '-') f = -1;
    for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
    x *= f;
}

int n;
int w[N], s[N];
db d[N], mx[N], mn[N];

bool check(db t) {
    for (int i = 1; i <= n; ++i) d[i] = s[i] - t * i;
    mn[1] = d[1], mx[n-1] = d[n-1];
    for (int i = 2; i < n - 1; ++i) mn[i] = min(mn[i-1], d[i]);
    for (int i = n - 2; i; --i) mx[i] = max(mx[i+1], d[i]);
    for (int i = 2; i < n; ++i)
        if (mx[i] - mn[i-1] > d[n]) return 0;
    return 1;
}

int main() {
    read(n);
    for (int i = 1; i <= n; ++i) read(w[i]), s[i] = s[i-1] + w[i];
    db l = 0, r = (s[n] - s[n-1] + s[1]) / 2.0;
    while (r - l > eps) {
        db mid = (l + r) / 2.0;
        if (check(mid)) l = mid;
        else r = mid;
    }
    printf("%.3lf", l);
    return 0;
}

「USACO14MAR」破坏Sabotage

原文:https://www.cnblogs.com/hlw1/p/12260544.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!