前言

大约一年前,我在机房学“斜率优化”

一年后的今天,我在机房学“斜率优化”

... ...

题目

Consider a simple sequence which only contains positive integers as a1, a2 ... an, and a number k. Define ave(i,j) as the average value of the sub sequence ai ... aj, i<=j. Let’s calculate max(ave(i,j)), 1<=i<=j-k+1<=n.

Input

There multiple test cases in the input, each test case contains two lines.
The first line has two integers, N and k (k<=N<=10^5).
The second line has N integers, a1, a2 ... an. All numbers are ranged in [1, 2000].

Output

For every test case, output one single line contains a real number, which is mentioned in the description, accurate to 0.01.

Sample Input

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

Sample Output

6.50

题目大意

读入N个正整数a[1]...a[n],和一个整数k。

定义区间平均值ave(i, j)表示一个连续子区间a[i]...a[j]的元素的平均值。

求最大的区间平均值max(ave(i, j)) 1<=i<=j-k+1<=n.

分析

此乃~斜率优化板题也~

参考博客&特别鸣谢:https://www.cnblogs.com/Free-rein/archive/2012/08/09/2630190.html


解题思路

首先一定会设序列ai的部分和:Si=a1+a2+…+ai,,特别的定义S0=0。

这样可以很简洁的表示出目标函数ave(i,j)=(Sj-S(i-1))/(j-(i-1))!

如果将S函数绘在平面直角坐标系内,这就是过点Sj和点Si-1直线的斜率!

于是问题转化为:平面上已知N+1 个点,Pi(i, Si),0≤i≤N,求横向距离大

于等于F的任意两点连线的最大斜率。


构造下凸折线

有序化一下,规定对i<j,只检查Pj向Pi的连线,对Pi不检查与Pj的连线。

也就是说对任意一点,仅检查该点与在其前方的点的斜率。于是我们定义点Pi

的检查集合为Gi = {Pj, 0≤j≤i-F},特别的,当i<F时,Gi为空集。

其明确的物理意义为:在平方级算法中,若要检查ave(a, b),那么一定有Pa∈Gb;

因此平方级的算法也可以这样描述,首先依次枚举Pb点,再枚举Pa∈Gb,同时检查k(PaPb)。//k为斜率


若将Pi和Gi同时列出,则不妨称Pi为检查点,Gi中的元素都是Pi的被检查点。

当我们考察一个点Pt时,朴素的平方级算法依次选取Gt中的每一个被检查点p,

考察直线pPt的斜率。但仔细观察,若集合内存在三个点Pi, Pj, Pk,且i<j<k,三个点形成如下图

所示的的关系,即Pj点在直线PiPk的上凸部分:k(Pi, Pj)>k(Pj,Pk),就很容易可以证明Pj点是多余的。

证明:

(一)若k(Pt, Pj) > k(Pt, Pi),那么可以看出,Pt点一定要在直线PiPj的上方,即阴

影所示的1号区域。

(二)同理若k(Pt, Pj) > k(Pt, Pk),那么Pt点一定要在直线PjPk的下

方,即阴影所示的2号区域。

综合上述两种情况,若PtPj的斜率同时大于PtPi和PtPk的,Pt点一定要落在两阴影的重叠部分,

但这部分显然不满足开始时t>j 的假设。于是,Pt落在任何一个合法的位置时,PtPj的斜率要么小于PtPi,

要么小于PtPk,即不可能成为最大值,因此Pj点多余,完全可以从检查集合中删去。这个结论告诉我们,

任何一个点Pt的检查集合中,不可能存在一个对最优结果有贡献的上凸点,因此我们可以删去每一个上凸点,

剩下的则是一个下凸折线。最后需要在这个下凸折线上找一点与Pt 点构成的直线斜率最大——显然这条直

线是在与折线相切时斜率最大,如图所示。


维护下凸折线——新元素入队的处理

这一小节中,我们的目标是:用尽可能少的时间得到每一个检查点的下凸折线。

算法首先从PF开始执行:它是检查集合非空的最左边的一个点,集合内仅有一个元素P0,

而这显然满足下凸折线的要求,接着向右不停的检查新的点:PF+1,PF+2, …, PN。

检查的过程中,维护这个下凸折线:每检查一个新的点Pt,就可以向折线最右端加入一个新的点Pt-F,

同时新点的加入可能会导致折线右端的一些点变成上凸点,我们用一个类似于构造凸包的过程依次删去这些上凸点,

从而保证折线的下凸性。由于每个点仅被加入和删除一次,所以每次维护下凸折线的平摊复杂度为O(1),

即我们用O(N)的时间得到了每个检查集合的下凸折线。


最后的优化:利用图形的单调性——寻找、更新答案的处理

最后一个问题就是如何求过Pt点,且与折线相切的直线了。一种直接的方法就是二分,每次查找的复杂度是O(log2N)。

但是从图形的性质上很容易得到另一种更简便更迅速的方法:

由于折线上过每一个点切线的斜率都是一定的,而且根据下凸函数斜率的单调性,如果在检查点Pt 时找到了折线上的已知一个切点A,

那么A以前的所有点都可以删除了:过这些点的切线斜率一定小于已知最优解,不会做出更大的贡献了。

于是另外保留一个指针不回溯的向后移动以寻找切线斜率即可,平摊复杂度为为O(1)。

至此,此题算法时空复杂度均为O(N),得到了圆满的解决。


总结——斜率优化的几大步骤(蒟蒻的大白话解释)

1.分析题目,列出转移方程或要求的“目标物”的式子

2.将方程或式子写作“y=kx+b”有时是“y/x=k”的形式,即直线表达式

3.维护一个双端队列,先处理队尾,再处理队首(决策队尾、队首元素的去留)

(“先队首再队尾导致错误”的具体例子请见:https://blog.csdn.net/qq_36294918/article/details/103641669)

4.转移方程或更新答案

5.输出答案,快乐结束


特别感谢:

《浅谈数形结合思想在信息学竞赛中的应用》---周源

提供了许多关于数形结合解题的思路。

代码

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN=1e5;
double sum[MAXN+5];
int q[MAXN+5];
int n,len;
inline char __getchar()
{static char buf[100000],*p1=buf,*p2=buf;return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline bool qread(int &x)
{char ch=__getchar();if(ch==EOF)return false;x=0;while(!(ch>='0'&&ch<='9'))ch=__getchar();while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=__getchar();return x;
}
void Solve()
{memset(q,0,sizeof(q));double Max=0;int head=0,tail=0;for(int i=len;i<=n;i++){int now=i-len;//长度至少为k //处理队尾 while(head<tail){double k1=(sum[q[tail]]-sum[q[tail-1]])/(q[tail]-q[tail-1]);double k2=(sum[now]-sum[q[tail]])/(now-q[tail]);//保证下凸 if(k1>=k2)tail--;//去掉上凸的点 elsebreak;}//入队 tail++;q[tail]=now;//处理队首 while(head<tail){double k1=(sum[q[head]]-sum[i])/(q[head]-i);double k2=(sum[q[head+1]]-sum[i])/(q[head+1]-i);//去掉不优的点 if(k1<=k2)head++;//下凸线中去掉斜率较小的点(从左往右)elsebreak;} double k=(sum[q[head]]-sum[i])/(q[head]-i);Max=max(Max,k);}printf("%.2f\n",Max);
}
int main()
{while(qread(n)&&qread(len)){sum[0]=0;for(int i=1;i<=n;i++){int x;qread(x);sum[i]=sum[i-1]+x;}Solve();}return 0;
}

【斜率优化】HDU-2993——MAX Average Problem相关推荐

  1. HDU 2993 MAX Average Problem(斜率优化DP)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2993 题目大意:给定一个长度为n(最长为10^5)的正整数序列,求出连续的最短为k的子序列平均值的最大 ...

  2. hdu 2993 MAX Average Problem 斜率优化DP

    详见,算法合集之<浅谈数形结合思想在信息学竞赛中的应用>. #include<cstdio> #include<cstring> #include<algor ...

  3. HDU-2993--MAX Average Problem详解

    此题是关于DP的优化问题,具体解题思路贴在后面 此题大意: 读入一列正数N,a1, a2, -, aN,以及一个数F.定义ave(i,j)=ai到aj的平均值,j-i+1>=k, 求一个最大的a ...

  4. hdu 2829 Lawrence 斜率优化

    链接:http://acm.hdu.edu.cn/showproblem.php?pid=2829 Lawrence Time Limit: 2000/1000 MS (Java/Others)    ...

  5. FZU-2239 Daxia Yayamao's problem(斜率优化)

    Daxia & Yayamao's problem FZU - 2239 题解:f(x)=A*x+B 如果j>k,Aj>Ak,Aj*x+Bj>=Ak*x+Bk,则(Bj-Bk ...

  6. hdu 3507 Print Article(dp+斜率优化)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3507 题解:显然这题的递推很容易得到 dp[i]=dp[j]+(sum[i]-sum[j])^2+m ...

  7. HDU 3507 Print Article(斜率优化DP)

    题目链接 题意 : 一篇文章有n个单词,如果每行打印k个单词,那这行的花费是,问你怎么安排能够得到最小花费,输出最小花费. 思路 : 一开始想的简单了以为是背包,后来才知道是斜率优化DP,然后看了网上 ...

  8. HDU 3507 斜率优化入学习

    [题目链接] 点击打开链接 [题意]大概题意就是要输出N个数字a[N],输出的时候可以连续的输出,每连续输出一串,它的费用是 "这串数字和的平方加上一个常数M". [写在前面] 思 ...

  9. C++剑指offer:解题报告之DP优化学习记 (二) ——浅论DP斜率优化 (Print Article 【HDU - 3507】 )

    链接:https://share.weiyun.com/5LzbzAc 目录 前言 斜率优化前期准备 1.从状态转移方程出发 2.推理状态转移方程 对结论的进一步推导 干货!综合结论 判断斜率大小的方 ...

最新文章

  1. 面试官:说说Java中的信号量?Semaphore
  2. 修改用户名_新华美育查找用户名及修改密码的方法分享
  3. 使用Flash读取COOKIE
  4. ActiveMQ的安装搭建
  5. vue中mixins的理解
  6. OpenCV学习(7.16)
  7. 排名前100的PHP函数及分析
  8. 软件测试--缺陷报告
  9. 第八章 OGRE中合成器(也就是传说中的image-based rendering)以及如何在OGRE中对着色器的uniform变量传值
  10. 关于数据库设计是否需要加入(建立)外键
  11. 二次规划(QP)求解与序列二次规划(SQP)求解非线性规划问题
  12. 【转载】怎样编写CSS?
  13. 74cms 5.0.1版本文件包含漏洞复现
  14. 620集成显卡和mx250,独显有必要吗?英特尔UHD620核显对比MX150性能测试
  15. 前端实现 导出图片,导出PDF(截图原理)
  16. kubernetes系列之一:Kubernetes如何利用iptables对外暴露service
  17. html5背景图片能加链接,CSS中用背景图片做为超链接的方法
  18. python 调用航空公司的接口 获取机票数据 api简单案例
  19. Oracle公司及产品介绍
  20. 春季瘦身燃烧脂肪14种妙法

热门文章

  1. Xiyou_Linux兴趣小组面试题详解
  2. QGraphic view实例:利用QGraphicsItem与定时器实现动画效果:蝴蝶飞舞
  3. 关于基于Lattice Crosslink-NX系列FPGA用于图像采集、桥接和处理的应用总结分享
  4. 长沙应届毕业生学什么好?
  5. 《UnityAPI.SkinnedMeshRenderer蒙皮网格渲染器》(Yanlz+Unity+SteamVR+云技术+5G+AI+VR云游戏+BakeMesh+bones+立钻哥哥++OK++)
  6. 杨辉三角形(超级简单的Python实现方法)
  7. Creo 钣金设计视频教程
  8. 小米8 twrp recovery_小米多机型可刷入Flyme8 daily版 Android P 全新适配-支持13款
  9. ArcEngine——投影变换
  10. 用蓝牙耳机播放键激活PC小娜