HDU 2993 MAX Average Problem(斜率优化入门+单调队列)
来源:互联网 发布:仓库,财务办公软件 编辑:程序博客网 时间:2024/06/06 15:40
单调队列说明:
单调队列,顾名思义就是具有单调性的队列,一般的队列只能从队尾入队、队首出队;为了保持单调队列的单调性,单调队列除具有这两种性质外,还可以从队尾出队。
以单增的单调队列为例,当元素t要入队时,先要从队尾依次弹出所有>=t的元素,再将t加在队尾。
举个例子,如果序列:1 3 -1 -3 10要构成单调队列,
先将元素“1”放入队列中,以初始化队列,
接着元素“3”要入队,队尾元素“1”比“3”小,因此“3”可以直接入队,队列变为1 3,
接着“-1”要入队,从队尾依次弹出元素“3”“1”后将“-1”入队,队列变为-1,
同理“-3”入队后,队列变为-3,
“10”入队后,队列变为-3 10
斜率优化
可以参考周源写的《浅谈数形结合思想在信息学竞赛中的应用》
题目大意:读入一列正数(包含N个数),求其中长度大于等于K的子串中所有数的平均值的最大值(K<=N<=10^5)。(最大平均值问题)
分析:1、读入一列正数,a1,a2,...,aN,以及一个数K。定义ave(i,j)=(ai+...+aj)/j-i+1,i<=j。求Max{ave(a,b),1<=a,b<=N,且a<=b+K-1},求一段长度大于等于K且平均值最大的子串。
2、如果单纯的枚举,每次枚举一对满足条件的(a,b),即a<=b-K+1,检查ave(a,b),并更新当前最大值。但是这题N很大,N^2的枚举算法显然不能用。
3、巧妙的使用斜率优化:
a)目标图形化:从第a到第b个数的平均值实际上就可以表示为(Sb-Sa)/(b-a),其中Si表示前i项和。那么如果在坐标系中用(i,Si)表示一个点,
则平均值就是两点确定的直线的斜率。这样化为几何图,就只需要找到最大的且符合题意的斜率就可以了。
b)构造下凸折线:类似于凸包。。这里寻找出现的可能的上凸点,将之去掉,就可以减少检查的范围。
关于上凸点:
如果三个数i,j,k,如果KK(i,j)>KK(j,k),其中KK表示两点所连直线的斜率,那么j点就是凸点。
这些上凸点不可能对最优结果又贡献。
c)维护下凸曲线
d)利用下凸曲线的单调性
4、Pi的检查集合为Gi={Pj,0<=j<=i-K},规定i<j。
代码:
#include<cstdio>
#include<iostream>
#include<cstring>#define findmax(a,b) (a)>(b)?(a):(b)using namespace std;int sum[100005];int que[100005];int a[100005];int getin() //getin()函数优化输入,如果有scanf读入,不管用c++还是G++提交都会CE{ char c; int dd; while(c=getchar(),c<'0'||c>'9'); dd=c-'0'; while(c=getchar(),c>='0'&&c<='9') dd=dd*10+c-'0'; return dd;}double findk(int i,int j) //求斜率{ double kk; kk=1.0*(sum[i]-sum[j])/(i-j); return kk;}int main(){ int n,k,i,j,head,rear; double ans; while(scanf("%d%d",&n,&k)!=EOF) { sum[0]=0; for(i=1;i<=n;i++) { sum[i]=sum[i-1]+getin(); } que[0]=0; //队列初始化 head=rear=ans=0; //ans存每次更新的最大平均值即最大斜率,head和rear是单调队列的头指针和尾指针 for(i=k;i<=n;i++) //从第K个开始检查,因为至少要相隔K个数 { j=i-k+1; while(head<rear&&findk(que[head],i)<=findk(que[head+1],i)) //维护单调队列,保证单增队列的头元素必是最大的 head++; ans=findmax(ans,findk(i,que[head])); //更新ans的值 while(head<rear&&findk(j,que[rear])<=findk(que[rear],que[rear-1])) //每次遇到上凸点就退队 rear--; que[++rear]=j; //把与检查的点相隔k的那个数加入队列 } printf("%.2lf\n",ans); } return 0;}
测试样例的模拟过程:
点(i,s[i])
(0,0)(1,6)(2,10)(3,12)(4,22)(5,25)(6,33)(7,38)(8,47)(9,51)(10,32)
首先,要从第6个点检查起,为什么呢,因为至少要相隔6个单位
检查(6,33),单调队列中只有一个(0,0),因为其他不符合要求
(0,0),(6,33),斜率为33/6=5.5
检查(7,38),(1,6)进单调队列,单调队列中有(0,0),(1,6),指针在(0,0)
计算(0,0),(7,38),斜率为5.43
计算(1,6)(7,38),斜率为5.33
指针不动,最大斜率还是5.5
检查(8,47),(2,10)进单调队列,单调队列中有(0,0),(1,6),(2,10),计算(0,0)跟(1,6)的斜率为6,(1,6)跟(2,10)的斜率为4,因此(1,6)弹出单调队列,单调队列中有(0,0),(2,10) //这里是(1,6)先退队,再把(2,10)加入队列
计算(0,0),(8,47),斜率为5.875
计算(2,10), (8,47),斜率为6.17
指针指向(2,10),最大斜率更新为6.17
……
后面自行补充
- HDU 2993 MAX Average Problem(斜率优化入门+单调队列)
- hdu 2993 MAX Average Problem (斜率优化dp入门)
- hdu 2993 MAX Average Problem(DP+斜率优化入门题)
- HDU 2993 MAX Average Problem 斜率优化
- HDU 2993 MAX Average Problem (斜率优化)
- hdu2993 MAX Average Problem(斜率+单调队列)
- HDU 2993 MAX Average Problem(斜率优化DP)
- HDU 2993 MAX Average Problem(斜率优化)
- HDU 2993 MAX Average Problem (斜率优化)
- HDU MAX Average Problem(斜率优化DP)
- HDU 2993 MAX Average Problem【斜率优化dp】
- hdu 2993 MAX Average Problem(DP+斜率优化)
- hdu 2993 MAX Average Problem 动态规划 斜率优化
- hdu 2993 MAX Average Problem 斜率优化DP
- hdu 2993 MAX Average Problem (dp斜率优化)
- hdu 2993 MAX Average Problem(斜率dp)
- hdoj MAX Average Problem 2993 (斜率优化DP)
- Hdu 2923 MAX Average Problem (DP_斜率优化)
- unbuntu desktop安装eclipse方法
- spring -bean 的创建过程
- 基于Mongodb进行分布式数据存储
- UVA oj 练习水题 算法入门经典(大数系列)
- Sql类型与.Net(C#)类型对应关系表
- HDU 2993 MAX Average Problem(斜率优化入门+单调队列)
- y460在ubuntu下开机关闭独显方法
- 冒泡排序
- wcf在IIS 承载的服务失败的解决方法
- 9个offer,12家公司,35场面试,从微软到谷歌,应届计算机毕业生的2012求职之路
- 关于内存分配诸多问题
- poj
- 面试题:如何从三亿个整数里面找出不重复的数字的个数
- Java多线程实现