CSP历年复赛题-P5017 [NOIP2018 普及组] 摆渡车

news/2024/10/7 10:16:25

原题链接:https://www.luogu.com.cn/problem/P5017

题意解读:先将问题进行抽象、建模。

设一条数轴,从左到右,每个点对应一个时刻,每个时刻可能有多个人到达,然后有若干个发车时刻,每两个发车时刻间隔必须>=m,每个人的等待时长就是到最近一个发车时刻的时间累加,计算所有人等待时间最小值。

对样例2进行模拟:

1时刻1人出发,等待0;6时刻两人出发,等待2;14时刻两人出发,等待2;总等待时长4,没有比4更小的等待时长。

解题思路:

如何来求解最小的等待时长?

设f[i]表示前i个时刻,最后在i时刻有发车时,所有人的最小等待时长。

那么考虑上一个发车时刻j,我知道i - j >= m,所以j <= i - m

得到递推关系:f[i] = min{f[j] + (j,i]之间所有人到i的时间之和}

(j,i]之间所有人到i的时间之和如何计算:

设cnt[i]表示前i时刻到达的人数,sum[i]表示前i时刻所有到达人的时刻之和,则有

(j,i]之间所有人到i的时间之和 = (cnt[i] - cnt[j]) * i - (sum[i] - sum[j])

所以,f[i] = min{f[j] + (cnt[i] - cnt[j]) * i - (sum[i] - sum[j])},j <= i - m

还要考虑i < m的情况,f[i] = cnt[i] * i - sum[i]

此时:整体时间复杂度是n^2,n是时刻最大值,在4000000,总体复杂度会超时,需要进行优化。

优化一:减少冗余状态

如果i时刻前m时间之内没有一个人,那么f[i]就不用通过递推算了,直接f[i] = f[i-m],判断条件是cnt[i] == cnt[i-m]

优化二:减少转移范围

当前j<=i-m,而如果j <= i-2m,即j到i之间车可以有两个往返,那么车必然可以增加一次发车,这样能带更多的人,所以j最好>i-2m且<=i-m

结果:f[最后一个达到的人的时刻] ~ f[最后一个达到的人的时刻+m]的最小值

100分代码:

#include <bits/stdc++.h>
using namespace std;const int N = 4000105;
int n, m, t, maxt;
int cnt[N], sum[N]; //设cnt[i]表示前i时刻到达的人数,sum[i]表示前i时刻所有到达人的时刻之和
int f[N]; //f[i]表示前i个时刻,最后在i时刻有发车时,所有人的最小等待时长。
int ans = INT_MAX;int main()
{cin >> n >> m;for(int i = 1; i <= n; i++){cin >> t;maxt = max(maxt, t);cnt[t]++, sum[t] += t;}//最后一个同学可能等到的时间maxt + m - 1for(int i = 1; i < maxt + m; i++){cnt[i] += cnt[i - 1];sum[i] += sum[i - 1];}memset(f, 0x3f, sizeof(f));for(int i = 0; i < maxt + m; i++){if(i >= m && cnt[i] == cnt[i - m]){f[i] = f[i - m];continue;}if(i < m)f[i] = cnt[i] * i - sum[i]; elsefor(int j = max(0, i - 2 * m + 1); j <= i - m; j++){f[i] = min(f[i], f[j] + (cnt[i] - cnt[j]) * i - (sum[i] - sum[j]));}}for(int i = maxt; i < maxt + m; i++) ans = min(ans, f[i]);cout << ans;return 0;
}

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hjln.cn/news/42807.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

etcd watch 实现原理

介绍 在 etcd 中,watch 是一个非常重要的特性,它可以让客户端监控 etcd 中的 key 或者一组 key,当 key 发生变化时,etcd 会通知客户端。本文将介绍 etcd watch 的实现原理。 etcdctl watch /test # 当 /test 的值发生变化时,会输出如下信息 PUT /test a PUT /test b DELET…

Vue TypeScript 实战:掌握静态类型编程

这篇文章介绍了如何在TypeScript环境下为Vue.js应用搭建项目结构,包括初始化配置、创建Vue组件、实现状态管理利用Vuex、配置路由以及性能优化的方法,旨在提升开发效率与应用性能。title: Vue TypeScript 实战:掌握静态类型编程 date: 2024/6/10 updated: 2024/6/10 excerpt…

INFINI Labs 产品更新 | Easysearch 1.8.2 发布优化 CCR 性能

INFINI Labs 产品又更新啦~,包括 Easysearch v1.8.0、Gateway、Console、Agent、Loadgen v1.25.0。本次各产品更新了很多亮点功能,如 Easysearch 新增数据写入限流功能,可实现节点、分片级限流;Gateway 修复数据迁移过程中因消费不及时解压缩导致部分数据记录损坏而丢失记录…

Nginx Rewrite

目录1.常用的Nginx 正则表达式2.location3.rewrite 1.常用的Nginx 正则表达式 ^ :匹配输入字符串的起始位置 $ :匹配输入字符串的结束位置 * :匹配前面的字符零次或多次。如“ol*”能匹配“o”及“ol”、“oll” + :匹配前面的字符一次或多次。如“ol+”能匹配“ol”及“ol…

3_@Autowired注解失效分析

1. Aware 接口 Aware 接口提供了一种[内置]的注入手段,可以注入BeanFactory, ApplicationContext。内置的注入和初始化不受扩展功能的影响,总会被执行,因此Spring 框架的内部类常使用它们。 InitializingBean 接口提供了一种[内置]的初始化手段。 Aware的作用就是注入与容器…

【内存管理】内存布局

ARM32位系统的内存布局图 32位操作系统的内存布局很经典,很多书籍都是以32位系统为例子去讲解的。32位的系统可访问的地址空间为4GB,用户空间为1GB ~ 3GB,内核空间为3GB ~ 4GB。为什么要划分为用户空间和内核空间呢? 一般处理器会把运行模式分为好几个,比如x86分为rang0 ~…

【esp32 项目】中断读取按键

原理图:图 按键部分图 单片机部分 程序:KEY_USR 引脚配置成上拉输入 在Arduino中,配置一个IO为上拉输入可以使用pinMode()函数和digitalWrite()函数。pinMode()函数用于设置引脚模式,而digitalWrite()函数用于设置上拉电阻。 以下是一个示例代码,展示如何将Arduino的数字引…

【操作系统】页表映射

页表的一些术语 现在Linux内核中支持四级页表的映射,我们先看下内核中关于页表的一些术语:全局目录项,PGD(Page Global Directory)上级目录项,PUD(Page Upper Directory)中间目录项,PMD(Page Middle Directory)页表项,(Page Table)大家在看内核代码时会经常看的以…