Hdu 2923 MAX Average Problem (DP_斜率优化)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2993


题目大意:给定一个长度为n的序列,从其中找连续的长度大于m的子序列使得子序列中的平均值最小。


解题思路:经典斜率优化DP,04年周维的论文《浅谈数形结合思想在信息学竞赛中的应用》有很详细的分析,这里只讲下实现。

     本题设子序列长度为x,子序列内和为y,使用单调队列来维护凸包的凸性。每次遍历到新的点时都要先把队尾的凸点给去掉,判断条件是y1 * x2 <= y2 * x1((x1,y1)是队尾的点,(x2,y2)是队尾的前一个点).  然后每次更新答案的时候,要把不可能是最优解的点给去掉,判断条件是y1 * x2 <= y2 * x1((x1,y1)是队头的点,(x2,y2)是队头的后一个点)。

     我的第一次ac代码700+ms,第二次加了输入外挂就成312ms了,然后将sum数组从double改成int成281ms,Rank3.    


测试数据:

Input:
10 6
6 4 2 10 3 8 5 9 4 1
1 1
1
10 3
1 2 3 1 2 3 4 5 6 1

Output:
6.50
1.00
5.00



C艹代码:

#include <stdio.h>
#include <string.h>
#define MAX 100001


double ans;
int sum[MAX],n,len;
int qu[MAX],head,tail;


double Solve_DP() {

    int i,j,k,pre,cur;
    double x1,x2,y1,y2;


    ans = 0;
    qu[tail] = 0;
    head = tail = 0;


    for (i = len; i <= n; ++i) {

        cur = i - len;
        while (head < tail) {
            //维护队列内凸包的凸性
            pre = qu[tail];
            x1 = cur - pre;
            y1 = sum[cur] - sum[pre];
            pre = qu[tail-1];
            x2 = cur - pre;
            y2 = sum[cur] - sum[pre];


            if (y1 * x2 <= y2 * x1) tail--;
            else break;
        }


        qu[++tail] = cur;
        while (head < tail) {
            //寻找最优的那个点
            cur = i;
            pre = qu[head];
            x1 = cur - pre;
            y1 = sum[cur] - sum[pre];
            pre = qu[head+1];
            x2 = cur - pre;
            y2 = sum[cur] - sum[pre];


            if (y1 * x2 <= y2 * x1) head++;
            else break;
        }


        pre = qu[head];
        double temp = (sum[i] - sum[pre]) * 1.0 / (i - pre);
        if (temp > ans) ans = temp;
    }


    return ans;
}
int Input() {
    
    char ch = ' ';
    while (ch < '0' || ch > '9')
        ch = getchar();
    int x = 0;
    while (ch >= '0' && ch <= '9')
        x = x * 10 + ch - '0',ch = getchar();
    return x;
}


int main()
{
    int i,j,k;


    while (scanf("%d%d",&n,&len) != EOF) {

        for (i = 1; i <= n; ++i)
            k = Input(),sum[i] = sum[i-1] + k;


        ans = Solve_DP();
        printf("%.2lf\n",ans);
    }
}

本文ZeroClock原创,但可以转载,因为我们是兄弟。

你可能感兴趣的:(Hdu 2923 MAX Average Problem (DP_斜率优化))