Luogu 5017 NOIP2018普及组T3 摆渡车 (斜率优化 + 必要的转移进行剪枝)
题意:
有 n 名同学要乘坐摆渡车从人大附中前往人民大学,第 i 位同学在第 ti 分钟去 等车。只有一辆摆渡车在工作,但摆渡车容量可以视为无限大。摆渡车从人大附中出发、 把车上的同学送到人民大学、再回到人大附中(去接其他同学),这样往返一趟总共花费 m 分钟(同学上下车时间忽略不计)。摆渡车要将所有同学都送到人民大学。
凯凯很好奇,如果他能任意安排摆渡车出发的时间,那么这些同学的等车时间之和最小为多少呢?
本人感觉自己语文不是那么的好,无法概括。
细节:
咳咳,此题细节都在题意之中嘻嘻嘻,原来懒还有这个好处。
分析:
round1:从时间入手状态迎刃而解:f[i] 表示以 i 作为发车时间的最小等车时间之和。
则转移就为:f[i] = min{ f[j] + Σj<tk≤i i-tk }
但是这个转移不免需要循环计算求和的内容,我们需要考虑将其利用 O(1) 进行计算完毕,考虑将这个式子进行打开:
Σj<tk≤i i-tk = i×Σj<tk≤i 1 - Σj<tk≤i tk,不难发现此时我们只需要预处理出 tk 出现位置的前缀数组 cnt[i],以及 tk 出现位置的值的前缀和 sum[i]。
这样方程进行进一步转化:f[i] = min{ f[j] + ( cnt[i] - cnt[j] ) × i - ( sum[i] - sum[j] ) }
最后观察其是否存在单调性,显然上方的 1D/1D 的动态规划需要进行斜率优化了,裸体希望有这些意识吧,常规套路,最后只需要维护一个斜率:
k = ( f[j2] + sum[j2] - f[j1] - sum[j1] ) / (cnt[j2] - cnt[j1]) 单调递增即可,具体方法详见本人的第一篇博客。
round2:确实从时间入手是一种思路,但是对于较小的 n 和 m 很多选手应该也会有想法,不难发现对于第 i 个人对应的等待时间 ti 它的上车时间是有一定的范围的,它就是[ ti , ti + m),因为当超出这个范围时要么是等车的人还没来,要么等车的人能乘坐上一班车子前往目的地,所以我们可以考虑一个状态:f[i][j] 表示第 i 个人乘车切在 ti + j 的时间中上了车的最小等车时间,其状态必须保证 i + 1 这个人无法上车,且 i 之前可能有人跟 i 一起在车上。
不难发现对于 i 之后的一个位置 k 其中这段区间 [i+1 , k] 的人上车时间可以进行计算,tmp 表示这段人的上车时间 = t[i] + j + m - t[i+k],所以我们出现了最原始的转移:
f[k][tmp] = f[i][j] + Σi+1<=x<=k(tmp + t[k] - t[x])
仍然需要把上方的转移优化成 O(1),使用一个裸的前缀和就可以优化掉了:
f[k][tmp] = f[i][j] + ( tmp + t[k] ) × ( k − i ) − ( sumt[k] − sumt[i] )
最后这个方程仍然可以进行优化,通过把 "我为人人" -> "人人为我" 就可以再一次进行斜率优化时间复杂度就可以变为 O(n),本人比较懒开始拒绝思考了。
代码:
Round1: #include<bits/stdc++.h>
#define MAXT 4000505
using namespace std; int n, m, cnt[MAXT], sum[MAXT], f[MAXT], que[MAXT], Maxt; int main(){
scanf("%d%d", &n, &m);
for (int i=; i<=n; i++){
int x;
scanf("%d", &x);
cnt[x]++, sum[x]+=x;
Maxt=max(Maxt, x);
}
for (int i=; i<Maxt+m; i++) cnt[i]+=cnt[i-], sum[i]+=sum[i-];
int head=, tail=;
for (int i=; i<Maxt+m; i++){
if (i>=m) {
while (head<tail && (f[que[tail]]+sum[que[tail]]-f[que[tail-]]-sum[que[tail-]])*(cnt[i-m]-cnt[que[tail]])>=(f[i-m]+sum[i-m]-f[que[tail]]-sum[que[tail]])*(cnt[que[tail]]-cnt[que[tail-]])) --tail;
que[++tail]=i-m;
}
while (head<tail && i*(cnt[que[head+]]-cnt[que[head]])>=(f[que[head+]]+sum[que[head+]]-f[que[head]]-sum[que[head]])) ++head;
f[i]=cnt[i]*i-sum[i];
if (head<=tail) f[i]=min(f[i], f[que[head]]+(cnt[i]-cnt[que[head]])*i-(sum[i]-sum[que[head]]));
}
int ans=;
for (int i=Maxt; i<Maxt+m; i++) ans=min(ans, f[i]);
printf("%d\n", ans);
return ;
}
Round2: #include<bits/stdc++.h>
using namespace std;
int t[],s[],f[][];
const int inf=;
inline int read()
{
int neg=,x=;
char c;
while((c=getchar())<''||c>'')
if(c=='-')
neg=-;
x=c-'';
while((c=getchar())>=''&&c<='')
x=x*+(c-'');
return x*neg;
}
int main()
{
int n=read(),m=read();
for(int i=;i<=n;i++)
t[i]=read();
sort(t+,t+n+);
for(int i=;i<=n;i++)
s[i]=s[i-]+t[i];
memset(f,0x7f,sizeof(f));
t[]=-inf;
f[][]=;
for(int i=;i<=n;i++)
{
int MAX=min(m-,t[i+]-t[i]);
for(int j=;j<=MAX;j++)
if(f[i][j]!=inf)
for(int k=;i+k<=n;k++)
{
int tmp=max(t[i]+j+m-t[i+k],);
f[i+k][tmp]=min(f[i+k][tmp],f[i][j]+(tmp+t[i+k])*k-(s[i+k]-s[i]));
}
}
int ans=inf;
for(int i=;i<m;i++)
ans=min(ans,f[n][i]);
printf("%d\n",ans);
return ;
}
Luogu 5017 NOIP2018普及组T3 摆渡车 (斜率优化 + 必要的转移进行剪枝)的更多相关文章
- NOIp2018普及组T3暨洛谷P5017 摆渡车:题解
题目链接:https://www.luogu.org/problemnew/show/P5017 emm,这次的真的不简单的,T3比T4难? 醉了... 蒟蒻肯定没有其他大佬讲的好啊,但肯定尽力,真的 ...
- P5017 [NOIP2018 普及组] 摆渡车
P5017 [NOIP2018 普及组] 摆渡车 题目 P5017 思路 将实际问题抽象后,不难发现这是一个 区间 \(DP\) 我们不妨认为时间是一条数轴,每名同学按照到达时刻分别对应数轴上可能重合 ...
- NOIP2018普及组复赛游记
2018年11月10日,NOIP2018普及组复赛. 这是我初中阶段最后一次复赛了. 和往常一样,我们在预定的早上7点,没有出发. 10分钟之后,人终于到齐了,于是出发了,一路无话. 到了南航,合照三 ...
- NOIP2018普及组初赛解题报告
本蒟蒻参加了今年的NOIP2018普及组的初赛 感觉要凉 总而言之,今年的题要说完全没有难度倒也不至于,还有不少拼RP的题,比如第一次问题求解考逻辑推理,第一次完善程序考双链表等 下面我就和大家一起看 ...
- P5018 [NOIP2018 普及组] 对称二叉树
P5018 [NOIP2018 普及组] 对称二叉树 题目 P5018 思路 通过hash值来判断左右树是否相等 \(hl[i]\) 与 \(Hl[i]\) 是防止hash冲突, \(r\) 同理 注 ...
- NOIP2012 普及组 T3 摆花——S.B.S.
题目描述 小明的花店新开张,为了吸引顾客,他想在花店的门口摆上一排花,共m盆.通过调查顾客的喜好,小明列出了顾客最喜欢的n种花,从1到n标号.为了在门口展出更多种花,规定第i种花不能超过ai盆,摆花时 ...
- NOIP2008 普及组T3 传球游戏 解题报告-S.B.S.
题目描述 上体育课的时候,小蛮的老师经常带着同学们一起做游戏.这次,老师带着同学们一起做传球游戏. 游戏规则是这样的:n个同学站成一个圆圈,其中的一个同学手里拿着一个球,当老师吹哨子时开始传球,每个同 ...
- NOIP2011 普及组 T3 洛谷P1309 瑞士轮
今天题做太少,放道小题凑数233 题目背景 在双人对决的竞技性比赛,如乒乓球.羽毛球.国际象棋中,最常见的赛制是淘汰赛和循环赛.前者的特点是比赛场数少,每场都紧张刺激,但偶然性较高.后者的特点是较为公 ...
- NOIP2018普及组模拟赛
向老师给的模拟赛,还没普及组难... 题目在洛谷团队里. 第一试三道水题,我46分钟就打完了,然后就AK了. 第二试一看,除了第二题要思考一段时间之外,还是比较水的,但是我得了Rank倒1,115分. ...
随机推荐
- HDU-1556:Color the ball(前缀和)
Color the ball Time Limit: 9000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) T ...
- ( 2018 Multi-University Training Contest 2)
2018 Multi-University Training Contest 2) HDU 6311 Cover HDU 6312 Game HDU 6313 Hack It HDU 6314 Mat ...
- ES6字符串操作讲解(详细),字符串编码表,代码单元,码点的详细介绍。
以前用到字符串的方法时候,并不会深刻的去思考其中的原理,所以在es6新增的这些方法里就有点蒙圈了,于是想要搞清楚为什么会新增这些方法,以及如何使用这些方法. 在博客园上看见一篇大神SamWeb的总结, ...
- Spark Mllib里如何删除每一条数据中所有的双引号“”(图文详解)
不多说,直接上干货! 具体,见 Hadoop+Spark大数据巨量分析与机器学习整合开发实战的第13章 使用决策树二元分类算法来预测分类StumbleUpon数据集
- 第六章 设计程序架构 之 设计实现WebSocket策略
1. 概述 传统网页的通信方式是请求-响应模式,每次请求-响应都是新的连接.连接的建立和断开也是需要消耗资源的. WebSocket是基于TCP协议,实现单个连接上的双向通信. 本章内容包括: 异步读 ...
- [转]SqlServer索引的原理与应用
索引的概念 索引的用途:我们对数据查询及处理速度已成为衡量应用系统成败的标准,而采用索引来加快数据处理速度通常是最普遍采用的优化方法. 索引是什么:数据库中的索引类似于一本书的目录,在一本书中使用目录 ...
- SpringBoot 2.x (9):整合Mybatis注解实战
SSM框架再熟悉不过了,不过以前通常是使用XML写SQL语句 这里用SpringBoot整合Mybatis并且使用注解进行开发 依赖: <!-- Mybatis --> <depen ...
- sublime text less安装踩坑图文讲解(less无法生成css)
唉,怎么感觉做个前端几乎把所有的坑都踩遍了啊,别人按照网上安装了一遍就好使,我这里就死活不行. 先说一下我的问题:网上说的能安装的都按了,可是sublime就是不给我生成css文件,后来知道了,就是l ...
- 慢慢积累遇到的linux指令
sudo 用来以其他身份来执行命令,预设身份为root sudo apt install git 下载git sudo root 进入root身份(只有这个身份ubuntu和window系统之间才能共 ...
- sql server Cannot resolve the collation conflict between "Chinese_PRC_BIN" and "Chinese_PRC_CI_AS" in the equal to operation
今天查询二个db,出现这个错误,二种方法,一种是把db里的collation改成一样的:如果不方便可以直接在sql语句后面转一下: select * from table where crm_mscr ...