【POJ2018】【实数域上的二分】【dp】

传送门:http://poj.org/problem?id=2018;

 

大概题意是求一个正整数数列 A 的平均数最大 长度不小于 L 的子段

 

我们可以二分答案 判定是否有一个长度不小于L的子段 平均数不小于二分值

我们把数列数减去二分的答案 则判断是否一个长度不小于L的子段 和大于0

众所周知我们可以用两个前缀和的值相减来表示 

我们只用对于每个i记录在i-L前最小的sum就可以了

贴代码(同时注意一些实数域二分的技巧就好)

#include<iostream>
#include<cstdio>
using namespace std;
long long n,L;
double a[1000001],b[1000001],sum[1000001];
int main()
{
    scanf("%lld%lld",&n,&L);
    for(long long i = 1;i <= n;i++)
    scanf("%lf",&a[i]);
    double eps = 1e-5;
    double l = -1e6,r = 1e6;
    while (r - l > eps)
    {
        double mid = (l + r) / 2;
        for(long long i = 1; i <= n; i++) b[i] = a[i] - mid;
        for(long long i = 1; i <= n; i++) sum[i] = sum[i - 1] + b[i];
        double ans = -1e10;
        double min_val = 1e10;
        for(long long i = L; i <= n ; i++)
        {
            min_val = min(min_val, sum[i - L]);
            ans = max(ans, sum[i] - min_val);
        }
        if(ans >= 0) l = mid;
        else
        r = mid;
    }
    cout << int (r * 1000) << endl;
}
View Code

 

posted @ 2020-08-24 20:46  fhq_treap  阅读(279)  评论(0编辑  收藏  举报