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

洛谷P2115

题目描述

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

输入格式

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

\(2\) 到第 \(N+1\) 行:第 \(i+1\) 行包含一个整数 \(a_i\;(1\leq a_i\leq 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_{1\leq i<l\bigcup r<i\leq 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\n",ans);
}

原文链接: https://www.cnblogs.com/kkkek/p/12552262.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;

也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬

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

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/337216

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年3月1日 下午11:03
下一篇 2023年3月1日 下午11:03

相关推荐