HDU 2993 MAX Average Problem(斜率优化)

题目链接:Click here~~

题意:

给一个长度为 n 的序列,找出长度 >= k 的平均值最大的连续子序列。

解题思路:

斜率优化的例题。

先求出前缀和数组 sum[] ,然后问题转化成给出 n+1 个点求出两点横坐标差 >= k 的点对所能构成的最大斜率。

然后朴素的想法是对于每一个可能的序列末端点 i,去寻找集合 [1,j] (i-j+1 >= k)中与它能构成的最大斜率,不断更新最大值。复杂度 O(n^2)。

然后斜率优化的思想,是对于不断增长的集合 [1,j] 维护一个下凸曲线,每次找出曲线中的切线即为当前最优值。

找切线的时候,根据下凸曲线中切点斜率递增的性质,可以删除已经找到的切点之前的点。复杂度为 O(n)。

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;

const int N = 1e5 + 5;

typedef long long LL;

int a[N],sum[N],q[N];

bool useless(LL Xa,LL Xb,LL Xc){
    return (sum[Xc] - sum[Xb]) * (Xb - Xa) <= (sum[Xb] - sum[Xa]) * (Xc - Xb);
}

int main()
{
    int n,k;
    while(~scanf("%d%d",&n,&k))
    {
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            sum[i] = sum[i-1] + a[i];
        }
        int head = 0 , rear = -1;
        double ans = 0;
        for(int i=k;i<=n;i++)
        {
            while(head < rear && useless(q[rear-1],q[rear],i-k))
                --rear;
            q[++rear] = i - k;

            while(head < rear && useless(q[head+1],q[head],i))
                ++head;

            ans = max(ans,(sum[i] - sum[ q[head] ]) * 1.0 / (i - q[head]));
        }
        printf("%.2f\n",ans);
    }
    return 0;
}


你可能感兴趣的:(HDU 2993 MAX Average Problem(斜率优化))