【积累】想不到可以二分..

洛谷P2115

题目描述

给一组长度为 (N;(3leq Nleq100000)) 的整数数组 (a;(1leq a_ileq 10000)),要求必须删去一个连续区间 ([l,r]) ,且满足 ((2leq lleq rleq n-1)) ,求剩余区间的平均值的最小值。

输入格式

(1) 行:一个整数 (N;(3leq Nleq100000))

(2) 到第 (N+1) 行:第 (i+1) 行包含一个整数 (a_i;(1leq a_ileq 10000))

输出格式

(1) 行:一个实数,表示平均值的最小值,四舍五入保留三维小数。

样例

输入:

5
5
1
7
8
2

输出:

2.667

题解

对于一个满足题意的ans,有:

[frac{sum-sum[l,r]}{n-(r-l+1)}leq ans\ sum-sum[l,r]leq ans*(n-(r-l+1))\ sum_{i=1}^{l-1}a[i]+sum_{i=r+1}^{n}a[i]leq ans*(n-(r-l+1))\ sum_{1leq i<ligcup r<ileq n}a[i]-ans leq 0\ ]

所以二分ans,在check函数中判断即可。

代码

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+5;
const double eps=1e-6;

int a,n;
double sum[maxn];
bool eql(double a,double b){return fabs(a-b)<1e-9;}
bool check(double x)
{
    double mi=sum[1]-x;
    for(int i=2;i<n;i++)
    {
        if(sum[n]-sum[i]-x*(n-i)+mi<0||eql(sum[n]-sum[i]-x*(n-i)+mi,0))return 1;
        mi=min(mi,sum[i]-x*i);
    }
    return 0;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&a),sum[i]=sum[i-1]+a;
    double l=1,r=100000,mid,ans;
    while(l<r||eql(l,r))
    {
        mid=(l+r)/2;
        if(check(mid))ans=mid,r=mid-eps;
        else l=mid+eps;
    }
    printf("%.3lf
",ans);
}
原文地址:https://www.cnblogs.com/kkkek/p/12552262.html