【DP+斜率优化】 hdu2993 MAX Average Problem

来源:互联网 发布:淘宝客开店 编辑:程序博客网 时间:2024/06/07 12:17

MAX Average Problem

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

题意:一段数字序列, 求长度不小于 K 的平均值最大的子序列。

题解:不难写出dp方程dp[i]=max{(summ[i]-summ[j])/(i-j)}(j<i,i-j>=k)。这个肯定要超时,我们要进行优化。如果我们把(i,summ[i])看成一个点就会发现求最大值其实就是求哪两点连线的斜率最大,这个我们可以通过维护一个下凸曲线和二分查找很快的找到最大值。详细的可以看《浅谈数形结合思想在信息学竞赛中的应用》中的最大平均值问题。

ps:这题还要注意必须用输入挂,不然必超时。还要数据类型最好用long long 或double 。

代码:

#include<cstdio>#include<cstring>using namespace std;#define MAX 100005#define max(a,b) ((a)>(b)?(a):(b))int q[MAX];double summ[MAX];//dp[i]=max{(summ[i]-summ[j])/(i-j)}(j<i,i-j>=k)int idx[MAX];double cross(int a,int b,int c)//比较斜率{    double x0=idx[b]-idx[a];    double y0=summ[b]-summ[a];    double x1=idx[c]-idx[b];    double y1=summ[c]-summ[b];    return x0*y1-x1*y0;}int binarySearch(int l,int r,int id)//二分查找{    int mid;    for(;l<r;)    {        mid=(l+r)>>1;        if(cross(q[mid],q[mid+1],id)<0)           r=mid;        else           l=mid+1;    }    return l;}void scan(double &n){    char c;    for(;c=getchar(),c<'0'||c>'9';);    n=c-'0';    for(;c=getchar(),c>='0'&&c<='9';)        n=n*10+c-'0';}int main(){    int n,k;    int back;    double cnt,ans;    for(;~scanf("%d%d",&n,&k);)    {        summ[0]=idx[0]=0;        for(int i=1;i<=n;++i)        {            //scanf("%lf",&cnt);            scan(cnt);            summ[i]=summ[i-1]+cnt;            idx[i]=i;        }        ans=back=0;        for(int i=k;i<=n;++i)        {            for(;back>1&&cross(q[back-1],q[back],i-k)<0;--back);            q[++back]=i-k;            int opt=binarySearch(1,back,i);            cnt=(summ[q[opt]]-summ[i])/(idx[q[opt]]-idx[i]);            ans=max(ans,cnt);        }        printf("%.2f\n",ans);    }    return 0;}
来源:http://blog.csdn.net/acm_ted/article/details/7910362

原创粉丝点击