<更新提示>

<第一次更新>摆渡车的题解我已经写过一遍了,在这里,这次主要从斜率优化的角度讲一下摆渡车,并总结一下斜率优化会出现的一些奇奇怪怪的错误。


<正文>

摆渡车

Description

有 n 名同学要乘坐摆渡车从人大附中前往人民大学,第 i 位同学在第 titi分钟去 等车。只有一辆摆渡车在工作,但摆渡车容量可以视为无限大。摆渡车从人大附中出发、 把车上的同学送到人民大学、再回到人大附中(去接其他同学),这样往返一趟总共花费m分钟(同学上下车时间忽略不计)。摆渡车要将所有同学都送到人民大学。

凯凯很好奇,如果他能任意安排摆渡车出发的时间,那么这些同学的等车时间之和最小为多少呢?

注意:摆渡车回到人大附中后可以即刻出发。

Input Format

第一行包含两个正整数 n,m,以一个空格分开,分别代表等车人数和摆渡车往返 一趟的时间。

第二行包含 n 个正整数,相邻两数之间以一个空格分隔,第 i 个非负整数 ti代 表第 i 个同学到达车站的时刻。

Output Format

输出一行,一个整数,表示所有同学等车时间之和的最小值(单位:分钟)。

Sample Input

5 5
11 13 1 5 5

Sample Output

4

解析

如果考虑斜率优化的思路的话,我们可以这样设置状态:\(f_i\)代表到了时间点\(i\),所有同学等待时间的最小和。那么就可以这样写状态转移方程:

\[f_i=min_{j\leq i-m}\{f_j+\sum_{j<t_k\leq i}(i-t_k)\}
\]

然后可以用前缀和把求和式拆一下,设\(cnt_i\)代表到时间点\(i\)位置已经到达过车站的学生个数,\(sum_i\)代表已经到达过车站的学生的到达时间总和,则原方程可以写为:

\[f_i=min_{j\leq i-m}\{f_j+(cnt_i-cnt_j)*i-(sum_i-sum_j)\}
\]

好了,看到有\(i,j\)乘积项就可以考虑斜率优化了,我们再整理一下式子:

\[f_i=min_{j\leq i-m}\{f_j+sum_j-cnt_j*i\}+cnt_i*i-sum_i
\]

假设找到了最优的决策点\(j\),那么就有:

\[f_i=f_j+sum_j-cnt_j*i+cnt_i*i-sum_i\\f_j+sum_j=cnt_j*i+f_i-cnt_i*i+sum_i
\]

把\(f_j+sum_j\)看做\(y\),把\(cnt_j\)看做\(x\),把\(i\)看作\(k\),把\(f_i-cnt_i*i+sum_i\)看做\(b\),这就是直线方程了,然后直接维护下凸壳,利用决策单调性转移就可以了。

但其实这道题还没那么简单,其实还有如下几个问题:

\(1.\) 变量\(j\)有取值范围,需满足\(j\leq i-m\)。

\(2.\) 计算斜率可能出现分母为\(0\)。

\(3.\) \(f\)数组缺少部分初值。

对于第一个问题,我们采用分层推入队列的方法:在维护单调队列时,每当完成了对\(f_i\)的转移,我们应尝试把\(i-m+1\)这一个决策点推入队列,这样就能保证满足决策变量\(j\)的取值范围合法,其他题也是一样的。

对于第二个问题,计算斜率时分母为\(0\)就对应了坐标系内两个点坐标横坐标相同,但是纵坐标不同的情况。相应地,我们将这种情况视为两点之间的斜率为\(+\infty\)或\(-\infty\)(按照两点位置判断)处理即可,这样处理既简单,又对正确性没有影响。

第三个问题就对应了第一个问题,对于前\(m\)的点,显然我们是没有初值的,也无法用单调队列转移,所以我们必须要暴力对前\(m\)个状态进行更新,才能进行斜率优化,这个就根据\(dp\)式来更新就可以了。

\(Code:\)

#include <bits/stdc++.h>
using namespace std;
const long long N=1e6+20,M=1e6+20,T=9e6+20,INF=1e18;
long long n,m,maxT,c[T],s[T],f[T];
long long q[T],head,tail,ans=INF;
inline void input(void)
{
scanf("%lld%lld",&n,&m);
for (int i=1;i<=n;i++)
{
long long t;scanf("%lld",&t);
maxT = max(t,maxT);
s[t] += t; c[t] ++;
}
}
inline void init(void)
{
for (int i=1;i<=maxT+m;i++)
c[i] += c[i-1] , s[i] += s[i-1];
}
inline double slope(int x,int y)
{
if ( c[x] == c[y] ) return f[y]+s[y] > f[x]+s[x] ? INF * 1.0 : INF * -1.0;
return ( 1.0 * (f[y]+s[y]) - 1.0 * (f[x]+s[x]) ) / ( 1.0 * (c[y]) - 1.0 * (c[x]) );
}
//f[i] = min{f[j]+(c[i]-c[j])*i-(s[i]-s[j])}
inline void dp(void)
{
head = tail = 1; q[tail] = 0;
for (int i=1;i<m;i++)
f[i] = c[i] * i - s[i];
for (int i=m;i<=maxT+m;i++)
{
while ( head<tail && slope(q[head],q[head+1]) <= 1.0 * i ) head++;
f[i] = f[q[head]] + (c[i]-c[q[head]]) * i - (s[i]-s[q[head]]);
while ( head<tail && slope(q[tail-1],q[tail]) >= slope(q[tail],i-m+1) ) tail--;
q[++tail] = i-m+1;
if (i>=maxT) ans = min(ans,f[i]);
}
}
int main(void)
{
input();
init();
dp();
printf("%lld\n",ans);
return 0;
}

总结

其实本题中的这一些问题就对应了斜率优化题中可能会出现的种种问题,以下我们对斜率优化总结一下:

解题基本思路:

\(1.\) 写出状态转移方程,看看能不能用斜率优化

\(2.\) 如果可以斜率优化,将方程改写为直线方程的形式,先用数形结合法尝试做一下

\(3.\) 如果可行,尝试证明一下决策单调性,用代数法推一推

\(4.\) 看看是什么类型的斜率优化:取\(min\)就维护下凸壳,取\(max\)就维护上凸壳

\(5.\) 注意一下\(i,j\)乘积项的符号,如果是负数一般把负号看成是与\(j\)有关项的而非斜率项的,然后在坐标系内重新画一下图,看看维护的到底是什么

\(6.\)最后看单调性会不会出问题,如果决策单调性出问题就用二分答案,如果凸壳不能单调维护就用\(cdq\)分治

常见问题:

\(1.\) 决策变量有取值范围,在推入队列的时候改为推入可取的决策变量

\(2.\) \(dp\)数组有部分初值无法用斜率优化转移得到(决策变量被取值范围限制),暴力先转移初值

\(3.\) 斜率会出现整数被\(0\)除,特判返回\(+\infty\)或\(-\infty\)

\(4.\) 计算斜率可能会出锅,\(slope\)函数尽量公式化:数值大的下标为\(y\),数值小的下标为\(x\),计算时用\(val(y)-val(x)\)

\(5.\) 单调队列要注意:必须在队列内有至少两个元素才能删除队首或队尾

\(6.\) 浮点数运算很容易出问题,计算斜率或比较大小时记得转为\(double\)类型

\(7.\) 精度可能会出问题,适当时计算斜率的除法要转为乘法

\(8.\) 考虑单调队列内是否要存一个转移初值(如\(0\))

\(9.\) \(dp\)数组的初值:\(+\infty\)或\(-\infty\)或\(0\),是否要\(long\ long\),无穷要开够大

\(10.\) 弹出队首不优元素和队尾不在下凸壳内元素比较斜率时,请将等号加上(\(<\)尽量写成\(\leq\),\(>\)尽量写成\(\geq\))

\(11.\) 写二分,请按模板来:\(while\)循环写\(l<r\),每一次计算\(slope(q[mid],q[mid+1])\),若小于等于斜率关键值,则\(l=mid+1\),反之\(r=mid\),最后返回\(q[l]\)

\(12.\)写\(cdq\)分治,也请按模板来:记得在递归子问题前先左右按编号大小分一下,避免出现\(f_i\)转移到\(f_j\)但是\(j>i\)的情况

\(cdq\)分治和二分的模板见『任务安排 斜率优化及其变形』,另外一片斜率优化数形结合入门博客见『玩具装箱TOY 斜率优化DP』,简单总结博客见『土地征用 Land Acquisition 斜率优化DP』


<后记>

『摆渡车 斜率优化dp及总结』的更多相关文章

  1. 『土地征用 Land Acquisition 斜率优化DP』

    斜率优化DP的综合运用,对斜率优化的新理解. 详细介绍见『玩具装箱TOY 斜率优化DP』 土地征用 Land Acquisition(USACO08MAR) Description Farmer Jo ...

  2. 【学习笔记】动态规划—斜率优化DP(超详细)

    [学习笔记]动态规划-斜率优化DP(超详细) [前言] 第一次写这么长的文章. 写完后感觉对斜优的理解又加深了一些. 斜优通常与决策单调性同时出现.可以说决策单调性是斜率优化的前提. 斜率优化 \(D ...

  3. bzoj-4518 4518: [Sdoi2016]征途(斜率优化dp)

    题目链接: 4518: [Sdoi2016]征途 Description Pine开始了从S地到T地的征途. 从S地到T地的路可以划分成n段,相邻两段路的分界点设有休息站. Pine计划用m天到达T地 ...

  4. bzoj-1096 1096: [ZJOI2007]仓库建设(斜率优化dp)

    题目链接: 1096: [ZJOI2007]仓库建设 Description L公司有N个工厂,由高到底分布在一座山上.如图所示,工厂1在山顶,工厂N在山脚.由于这座山处于高原内陆地区(干燥少雨),L ...

  5. [BZOJ3156]防御准备(斜率优化DP)

    题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=3156 分析: 简单的斜率优化DP

  6. 【BZOJ-1096】仓库建设 斜率优化DP

    1096: [ZJOI2007]仓库建设 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 3719  Solved: 1633[Submit][Stat ...

  7. BZOJ 1010: [HNOI2008]玩具装箱toy 斜率优化DP

    1010: [HNOI2008]玩具装箱toy Description P教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京.他使用自己的压缩器进行压缩,其可以将任意物品变成一堆,再 ...

  8. BZOJ 3156: 防御准备 斜率优化DP

    3156: 防御准备 Description   Input 第一行为一个整数N表示战线的总长度. 第二行N个整数,第i个整数表示在位置i放置守卫塔的花费Ai. Output 共一个整数,表示最小的战 ...

  9. HDU2829 Lawrence(斜率优化dp)

    学了模板题之后上网搜下斜率优化dp的题目,然后就看到这道题,知道是斜率dp之后有思路就可以自己做不出来,要是不事先知道的话那就说不定了. 题意:给你n个数,一开始n个数相邻的数之间是被东西连着的,对于 ...

随机推荐

  1. B端产品经理的金字塔能力模型

    工作这几年,时长思考,作为B端产品经理自己应该具备什么样的能力? 虽然工作依旧在有条不紊的进行,但是时常会陷入到对知识或者能力的焦虑当中.特别时是工作三五年,产品经理进阶门槛时. 虽然产品经理的能力是 ...

  2. 0x03 Python logging模块之Formatter格式

    目录 logging模块之Formatter格式 Formater对象 日志输出格式化字符串 LogRecoder对象 时间格式化字符串 logging模块之Formatter格式 在记录日志是,日志 ...

  3. Codeforces G. The Brand New Function(枚举)

    题目描述: The Brand New Function time limit per test 2 seconds memory limit per test 256 megabytes input ...

  4. DVWA的搭建

    DVWA的搭建 一.DVWA是什么? 一款渗透测试演练系统,俗称靶机. 二.如何搭建? Linux有成套的靶机,直接打开使用就可以,下面开始介绍Windows 下DVWA的搭建. 运行phpstudy ...

  5. 数据库中的gt,ge,lt,le的区别

    eq相等   ne.neq不相等,   gt大于, lt小于 gte.ge大于等于   lte.le 小于等于   not非   mod求模   is [not] div by是否能被某数整除   i ...

  6. AcWing 24. 机器人的运动范围

    习题地址 https://www.acwing.com/solution/acwing/content/2970/ 题目描述地上有一个 m 行和 n 列的方格,横纵坐标范围分别是 0∼m−1 和 0∼ ...

  7. 完美解决该死的ie6下select总是置于最上层bug

    <html> <head> <meta http-equiv="Content-Type" content="text/html; char ...

  8. 【LG5444】[APIO2019]奇怪装置

    [LG5444][APIO2019]奇怪装置 题面 洛谷 题目大意: 给定\(A,B\),对于\(\forall t\in \mathbb N\),有二元组\((x,y)=((t+\lfloor\fr ...

  9. c++primer(第五版) 阅读笔记

    快速阅读一遍c++ primer,复习c++ 1.本书代码:http://www.informit.com/store/c-plus-plus-primer-9780321714114 2.本书结构:

  10. Salesforce LWC学习(八) Look Up组件实现

    本篇参考https://www.salesforcelwc.in/2019/10/lookup-in-lwc.html,感谢前人种树. 我们做lightning的时候经常会遇到Look up 或者MD ...