前言

在考场被这个题搞自闭了,那个时候自己是真的太菜了。qwq
现在水平稍微高了一点,就过来切一下这一道\(DP\)经典好题。
附加一个题目链接:【洛谷】

正文

虽然题目非常的简短,但是解法有很多。
我按照时间复杂度来写一下一些做法。
博主只考虑了一些基于时间的做法,其他的再补。。

时间复杂度:\(O(t^2n)\)

借鉴sooke大佬的想法,把问题抽象成一个数轴。
每一个人上车的时间就是在数轴上可能重合的一个点,一辆公交车抽象成在数轴上的一条长度为m的线段进行一次覆盖。
因为考虑到上下车时间忽略不计,那么就把这个线段看成一个左开右闭的线段。
那么问题就变成了,所有人到覆盖这个点的线段右端点的距离之和,我们的任务就是让这个和最小。
如果文字看不懂,那么就看下图:

上图中的绿色方块部分就是线段覆盖的区间。
因为我们将公交车抽象成了一个左开右闭的线段,下一辆车最早可以出发的时间
至于为什么要左开右闭,是因为可以正向的做\(DP\)。
转化出来了一个非常经典的模型。
\(f_i\)表示最后一段的右端点是\(i\),对于每一个\(i\)我们需要找到转移到\(f_i\)的决策。
枚举\(j\)也就是前一段。
可以得到一个基础的\(DP\)方程:\(f_i=min(f_j+\sum^{}_{j<tk\leq i}i-t_k)\)
其中的\(t_k\)是每一个人到的时间。也就是数轴上的各个点。
什么优化都没有的\(DP\),枚举\(i,j,k\)。
期望得分:30分

时间复杂度:\(O(t^2)\)

考虑优化上述\(DP\)。
先把式子搬下来
\[f_i=min(f_j+\sum^{}_{j<tk\leq i}i-t_k)\]
由\(\sum\)可以发现可以用前缀和优化。
那么我们就试着把这个\(\sum\)拆成前缀和的形式。
\[\sum^{}_{j<tk\leq i}i-t_k=\sum^{}_{j<tk\leq i}i-\sum^{}_{j<tk\leq i}t_k=(psum_i-psum_j)\times i-(tsum_i-tsum_j)\]
其中的\(psum\)表示的是在区间内符合的个数,\(tsum\)表示的是在区间内符合的时间的总和。

#include <bits/stdc++.h>
using namespace std;
namespace IOstream {#define gc getchartemplate <typename T>inline void read(T &x) {x = 0; T fl = 1; char c = 0;for (; c < '0' || c > '9'; c = gc()) if (c == '-') fl = -1;for (; c >= '0' && c <= '9'; c = gc()) x = (x << 1) + (x << 3) + (c ^ 48);x *= fl;}#undef gc
} using namespace IOstream;
const int N = 4e6 + 506;
const int inf = 0x3f3f3f3f;
int psum[N], tsum[N], f[N];
int n, m, t;
int main() {read(n); read(m);if (m == 1) { puts("0"); return 0; }for (int i = 1, x; i <= n; i ++) {read(x); t = max(x, t);psum[x] ++; tsum[x] += x;}for (int i = 0; i < t + m; i ++) {tsum[i] += tsum[i - 1]; psum[i] += psum[i - 1];}memset(f, inf, sizeof(f));for (int i = 0; i < t + m; i ++) {f[i] = psum[i] * i - tsum[i];for (int j = 0; j + m <= i; j ++) {f[i] = min(f[i], f[j] + (psum[i] - psum[j]) * i - (tsum[i] - tsum[j]));}}int ans = inf;for (int i = t; i < t + m; i ++) ans = min(ans, f[i]);cout << ans << endl; return 0;
}

时间复杂度:\(O(t)\)

再是这个式子
\[f_i=min(f_j+\sum^{}_{j<tk\leq i}i-t_k)\]
可以发现这个东西和斜率优化的基本套路是一样的。
那么稍微推导一下
将前缀和的式子拿出来\(f_i=f_j+(psum_i-psum_j)\times i-(tsum_i-tsum_j)\)
把和\(i\)有关的项都放到一边,把其他的\(j\)和\(k\)的项放到另外一边。
最终可以化简为
\[\underline{f_j+tsum_j}_y=\underline{i}_k\times \underline{psum_i}_x+\underline{(f_i+psum_j\times i-tsum_i)}_b\]

对应下面这个东西
\[y=kx+b\]

开始斜率优化。
可以发现斜率\(i\)递增,然后维护下凸包。

#include <bits/stdc++.h>
using namespace std;
namespace IOstream {#define gc getchartemplate <typename T>inline void read(T &x) {x = 0; T fl = 1; char c = 0;for (; c < '0' || c > '9'; c = gc()) if (c == '-') fl = -1;for (; c >= '0' && c <= '9'; c = gc()) x = (x << 1) + (x << 3) + (c ^ 48);x *= fl;}#undef gc
} using namespace IOstream;
typedef double db;
const int N = 4e6 + 506;
const int inf = 0x3f3f3f3f;
int psum[N], tsum[N], f[N], q[N << 1];
// psum记录的是人数前缀和,tsum表示总时间的前缀和
int n, m, T;
db Y(int i) { return 1.0 * (- f[i] - tsum[i]); }
db X(int i) { return 1.0 * (- psum[i]); }
db slope(int i, int j) { return (Y(i) - Y(j)) / (psum[i] == psum[j] ? 1e-9 : (X(i) - X(j))); }
int main() {read(n); read(m);if (m == 1) { puts("0"); return 0; }for (int i = 1, x; i <= n; i ++) {read(x); T = max(x, T);psum[x] ++; tsum[x] += x;}for (int i = 0; i < T + m; i ++) {tsum[i] += tsum[i - 1]; psum[i] += psum[i - 1];}int h = 1, t = 0; for (int i = 0; i < T + m; i ++) {if (i >= m) {while (h < t && slope(q[t - 1], q[t]) >= slope(q[t], i - m)) t --;q[++ t] = i - m; }while (h < t && slope(q[h], q[h + 1]) <= i) h ++; f[i] = psum[i] * i - tsum[i];int j = q[h];if (h <= t) f[i] = min(f[i], f[j] + (psum[i] - psum[j]) * i - (tsum[i] - tsum[j])); }int ans = inf;for (int i = T; i < T + m; i ++) ans = min(ans, f[i]);cout << ans << endl; return 0;
}

转载于:https://www.cnblogs.com/chhokmah/p/10795432.html

「洛谷5017」「NOIP2018」摆渡车【DP,经典好题】相关推荐

  1. [洛谷 P4084 USACO17DEC] Barn Painting G (树形dp经典)

    [洛谷 P4084 USACO17DEC] Barn Painting G 题目链接 大致题意: 给定一颗N个节点组成的树,3种颜色,其中K个节点已染色,要求任意两相邻节点颜色不同,求合法染色方案数 ...

  2. [洛谷 1365] WJMZBMR打osu! / Easy {期望DP}

    题目 https://www.luogu.org/problemnew/show/P1365 解题思路 这是我做的第三道期望DP.跟前两道的不同之处,在于它连续的一段具有不确定性且没有给出n的范围.所 ...

  3. 「LuoguP4995」「洛谷11月月赛」 跳跳!(贪心

    题目描述 你是一只小跳蛙,你特别擅长在各种地方跳来跳去. 这一天,你和朋友小 F 一起出去玩耍的时候,遇到了一堆高矮不同的石头,其中第 ii 块的石头高度为 h_ihi​,地面的高度是 h_0 = 0 ...

  4. 【洛谷 P4934】 礼物 (位运算+DP)

    题目链接 位运算+\(DP\)=状压\(DP\)?(雾 \(a\&b>=min(a,b)\)在集合的意义上就是\(a\subseteq b\) 所以对每个数的子集向子集连一条边,然后答案 ...

  5. 洛谷P3349:小星星(容斥dp)

    解析 先安利一波洛谷上我介绍如何用暴力日过去的博客 现在开始务正业 考虑把dp记录状态的一维s去掉 这样单次转移复杂度变成n3n^3n3 但是这样显然会算多啊! 因为一个编号可能会用很多次 考虑容斥 ...

  6. 【洛谷新手村解题报告二】C++语言,一题多解,思路和WA反思

    [洛谷新手村解题报告二] 循环!循环!循环! 数组 继续上次的一!开始循环第二题 循环!循环!循环! 第二题 级数求和 [1/2] 已知:Sn= 1+1/2+1/3+-+1/n 显然对于任意一个整数 ...

  7. POJ3612 洛谷P2885 [USACO07Nov] Telephone Wire 架设电话线 dp

    题目链接:洛谷 POJ 题目描述 最近,Farmer John的奶牛们越来越不满于牛棚里一塌糊涂的电话服务 于是,她们要求FJ把那些老旧的电话线换成性能更好的新电话线. 新的电话线架设在已有的 N ( ...

  8. [洛谷CF235B] Let‘s Play Osu! {期望DP}

    题目 https://www.luogu.org/problemnew/show/CF235B 解题思路 跟[洛谷 1654] OSU! {期望DP}一样. 代码 #include<cstdio ...

  9. 洛谷 P2196 [NOIP1996 提高组] 挖地雷(dp简单题)

     题目链接: [NOIP1996 提高组] 挖地雷 - 洛谷 思路: 典型的dp题,由于题目规定了只能由编号小的地窖到编号大的,所以dp顺序是确定的,不需要进行拓扑排序,只需要判断 i,j 之间是否有 ...

  10. 「洛谷P1343」地震逃生 解题报告

    P1343 地震逃生 题目描述 汶川地震发生时,四川XX中学正在上课,一看地震发生,老师们立刻带领x名学生逃跑,整个学校可以抽象地看成一个有向图,图中有n个点,m条边.1号点为教室,n号点为安全地带, ...

最新文章

  1. 解决vue-awesome-swiper中swiper/css/swiper.css无法导入问题
  2. linux下批量修改文件名的方法
  3. 2017年11月01日普及组 I Got a Matrix!
  4. Spring-Bean的依赖注入分析-01
  5. 第一章计算机基础知识作业答案,第一章 计算机基础知识.doc第一次作业
  6. wow,My God,当当终于销售《走出软件作坊》了
  7. R语言任务视图:机器学习与统计学…
  8. java 可以重载等于号码_Java面试之Java基础4——重载与重写的区别
  9. HTML的SEO(搜索引擎优化)标准
  10. Topcoder SRM 637 (Div.2)
  11. 数仓 调度_大数据作业调度
  12. 关于AngularJS:
  13. 实验7 BindService模拟通信
  14. 浅谈中国古代服饰纹样中礼制精神的体现
  15. 关于销售的成本和收入
  16. 基于Python语言豆瓣电影数据挖掘与分析
  17. GEEM2引擎微端架设基本教程
  18. 微信小程序基于最新版1.0开发者工具分享-小试牛刀(视频) 发布流程
  19. get请求图片出现403 防盗链解决方式 no-referrer
  20. 回味陈年老酒----DOS

热门文章

  1. 教大家防止Jar包被反编译
  2. com.mysql.jdbc.jdbc2.optional.MysqlXADataSource 找不到
  3. 经典排序算法(七)--冒泡排序Bubble Sort
  4. C++ memset 踩坑(转载)
  5. 33. 把数组排成最小的数(C++版本)
  6. 二叉树最小结构(C++版本)
  7. 06. 当心C++编译器最烦人的分析机制
  8. 使用Connector/C++操作MySQL
  9. mysql中不重复_mysql中distinct的用法(不重复记录)
  10. mysql 流浪,流浪汉机器 – 如何找出mysql用户名/密码