Sabotage 二分

来源:互联网 发布:java 堆栈实现 编辑:程序博客网 时间:2024/05/21 22:27

题目链接:http://www.usaco.org/index.php?page=viewproblem2&cpid=419

题意:有1,000,000个整数,要求从第2个到n-1个之间,删去一段连续的数,使得剩余数的平均数最小。( 1<=所有数<= 1e6).

题解:二分法,二分一个平均密度p,使原序列均减去p,求得2~n-1的最大连续和,可得到剩余数的和的正负值。若为正,则p小于mid;否则,p大于mid。

代码:

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<vector>#include<cmath>using namespace std;const int N = 1e5+10;const double eps = 1e-4;double a[N],b[N],high,low,sum;int n;double get(){    double ans = 0,sum=0;    double fumax = -1e8;    int fl=1;    for(int i=2;i<=n-1;i++){        if(b[i]>0) fl=0;        fumax = max(fumax,b[i]);    }    if(fl) return fumax;    for(int i=2;i<=n-1;i++){        if(sum+b[i]>0) sum += b[i];        else sum = 0;        ans = max(ans,sum);    }    return ans;}double solve(){    while(high-low>eps){        double mid = (low+high)/2;        for(int i=1;i<=n;i++)            b[i] = a[i]-mid;        double maxd = get();        double tmp = sum-n*mid-maxd;        if(tmp < 0) high = mid;        else low = mid;    }    return low;}int main(){//    freopen("10.in","r",stdin);    cin >> n;    sum = 0;    high = 1;low = 1e8;    for(int i=1;i<=n;i++){        scanf("%lf",&a[i]);        sum += a[i];        high = max(a[i],high);        low = min(a[i],low);    }    double ans = solve();    printf("%.3lf\n",ans);    return 0;}


0 0
原创粉丝点击