hdu 2993 MAX Average Problem(斜率dp)

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

思路:

1,用一个单调队列来维护解集。

2,假设队列中从头到尾已经有元素a b c。那么当d要入队的时候,我们维护队列的上凸性质,即如果g[d,c]<g[c,b],那么就将c点删除。直到找到g[d,x]>=g[x,y]为止,并将d点加入在该位置中。

3,求解时候,从队头开始,如果已有元素a bc,当i点要求解时,如果g[b,a]<sum[i],那么说明b点比a点更优,a点可以排除,于是a出队。最后dp[i]=getDp(q[head])。

参考博客:http://blog.csdn.net/dgq8211/article/details/12443049

http://www.cnblogs.com/jackge/archive/2013/04/17/3026219.html

#include<iostream>
#include<cstdio>
#include<cstring>

using namespace std;

const int maxn=100010;

double sum[maxn];
int q[maxn];

double cross(int i,int j,int k){
    double tmp;
    tmp=(k-i)*(sum[j]-sum[i])-(j-i)*(sum[k]-sum[i]);
    return tmp;
}

double max(double a,double b){
    return a>b?a:b;
}

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

double f(int i,int k){
    i=q[i];
    return (sum[k]-sum[i])/(k-i);
}

int main(){

    //freopen("input.txt","r",stdin);

    int n,k;
    while(~scanf("%d%d",&n,&k)){
        sum[0]=0;
        int i,j;
        for(i=1;i<=n;i++)
            sum[i]=sum[i-1]+Input();
        int head=0,rear=0;
        double ans=0;
        for(i=k;i<=n;i++){
            j=i-k;
            while(head<rear && cross(q[rear-1],q[rear],j)>=0)
                rear--;
            q[++rear]=j;
            while(head<rear && f(head+1,i)>=f(head,i))
                head++;
            ans=max(ans,f(head,i));
        }
        printf("%.2lf\n",ans);
    }
    return 0;
}

你可能感兴趣的:(hdu 2993 MAX Average Problem(斜率dp))