JZOJ 5415. 【NOIP2017提高A组集训10.22】公交运输
题目
城市中有一条长度为 \(n\) 的道路,每隔 \(1\) 的长度有一个公交车站,编号从 \(0\) 到 \(n\),学校在 \(0\) 号车站的位置。其中每个公交车站(除了 \(n\) 号车站)有两个属性 \(c_i\) 和 \(v_i\),代表从这个公交车站出发的公交车的性质。\(c_i\) 代表这个从i出发的公交车,相邻两个停靠站之间的距离。\(v_i\) 表示每坐 \(1\) 站的花费。
注意,一辆公交车出发后会向 \(n\) 号车站的方向行进。同时,一名乘客只能从起点站上车,但可以从任意停靠站下车。校庆志愿者小 \(Z\) 为了帮助校友查询有关城市交通费用的问题,想知道从 \(0\) 号车站(也就是学校)出发,到达每个公交车站的最小花费,于是他找到了你。
数据规模
对于 30% 的数据满足,\(1 \le n \le 5000\)
对于 60% 的数据满足,\(1 \le n \le 10^5\)
对于另 20% 的数据满足,\(maxc = 1\)
对于 100% 的数据满足,\(1 \le n \le 10^6,1 \le maxc \le 10,1 \le ci \le maxc,1 \le vi \le 1000\)
数据存在梯度。
分析
30% 的数据
我们试着想 \(O(n^2)\) 的 \(dp\)
有 \(f_i = \min_{1 \le j < i,c_j | (i-j)}f_j + (i-j)/c_j*v_j\)
另 20% 的数据
既然有 \(maxc = 1\) 说明所有的 \(c_j=1\)
也就是说我们从 \(0\) 点开始坐车,一遇到 \(v_i\) 更小的就可以换乘,必然更优
\(O(n)\) 扫一遍就好了
100% 的数据
考虑继续优化 \(dp\)
很明显只能上斜率优化了!
很明显用不了斜率优化!
观察 \(f_i = f_j+ (i-j)/c_j*v_j\)
若需 \(c_j|(i-j)\),那么 \(i \equiv j \pmod {c_j}\)
所以我们要维护 \(i\) 的决策集合
只要 \(c_i\) 和 \(i \bmod {c_i}\) 两样东西就可以确定了
那我们就维护 \(maxc \times maxc\) 个决策集合
选用 \(vector\) 类型就好,我选择了链式前向星
然后怎么找最优决策?
我们先从题目中找性质
两站同属一个决策集合
如过后一个站的 \(v_i\) 小于 前一个站 \(v_i\), 前一个站就没有用了
然后我们就有了 \(v_i\) 单调递增
因为同属一个集合,\(c_i=c_j\) 所以 \(v_i/c_i\) 单调递增
记 \(p_i = v_i / c_i\)
那么 \(f_i = f_j+(i-j)*p_i\)
此时考虑斜率优化
若 \(j < k\) 且 \(j\) 更优
则
f_j+(i-j)*p_j < f_k+(i-k)*p_k \\
\frac{(f_j-j*p_j)-(f_k-k*p_k)}{p_k-p_j} < i
\end{aligned}
\]
因为 \(f_j-j*p_j\) 越来越小
所以最优决策在最后,用栈维护集合即可
\(Code\)
#include<cstdio>
#include<iostream>
using namespace std;
const int N = 1e6 + 5, INF = 0x3f3f3f3f;
int n, maxc;
int f[N], c[N], v[N], t[15][15];
struct node{int to, pre;}e[N];
inline void add(int c, int y, int to)
{
static int tot = 0;
e[++tot] = node{to, t[c][y]}, t[c][y] = tot;
}
inline double slope(int j, int k){return (f[j] - 1.0 * j * v[j] / c[j] - f[k] + 1.0 * k * v[k] / c[k]) / (v[k] - v[j]);}
inline void read(int &x)
{
x = 0; int f = 1; char ch = getchar();
while (ch < '0' || ch > '9') f = (ch == '-' ? -1 : f), ch = getchar();
while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
x *= f;
}
int buf[20];
inline void write(int x)
{
if (x < 0) putchar('-'), x = -x;
for (; x; x /= 10) buf[++buf[0]] = x % 10;
if (!buf[0]) buf[++buf[0]] = 0;
for (; buf[0]; putchar('0' + buf[buf[0]--]));
}
int main()
{
freopen("bus.in", "r", stdin);
freopen("bus.out", "w", stdout);
read(n), read(maxc);
for(register int i = 0; i < n; i++) read(c[i]), read(v[i]);
f[0] = 0, add(c[0], 0, 0);
for(register int i = 1; i <= n; i++)
{
f[i] = INF;
for(register int j = 1; j <= maxc; j++)
if (t[j][i % j])
{
int y = i % j;
while (e[t[j][y]].pre && slope(e[e[t[j][y]].pre].to, e[t[j][y]].to) < 1.0 * i / j) t[j][y] = e[t[j][y]].pre;
f[i] = min(f[i], f[e[t[j][y]].to] + (i - e[t[j][y]].to) * v[e[t[j][y]].to] / c[e[t[j][y]].to]);
}
if (i == n || f[i] == INF) continue;
int y = i % c[i];
while (t[c[i]][y] && v[e[t[c[i]][y]].to] >= v[i]) t[c[i]][y] = e[t[c[i]][y]].pre;
while (e[t[c[i]][y]].pre && slope(e[e[t[c[i]][y]].pre].to, e[t[c[i]][y]].to) < slope(e[t[c[i]][y]].to, i))
t[c[i]][y] = e[t[c[i]][y]].pre;
add(c[i], y, i);
}
for(register int i = 1; i <= n; i++)
if (f[i] == INF) putchar('-'), putchar('1'), putchar(' ');
else write(f[i]), putchar(' ');
}
JZOJ 5415. 【NOIP2017提高A组集训10.22】公交运输的更多相关文章
- [JZOJ 5437] [NOIP2017提高A组集训10.31] Sequence 解题报告 (KMP)
题目链接: http://172.16.0.132/senior/#main/show/5437 题目: 题解: 发现满足上述性质并且仅当A序列的子序列的差分序列与B序列的差分序列相同 于是我们把A变 ...
- 【JZOJ5428】【NOIP2017提高A组集训10.27】查询
题目 给出一个长度为n的序列a[] 给出q组询问,每组询问形如\(<x,y>\),求a序列的所有区间中,数字x的出现次数与数字y的出现次数相同的区间有多少个. 分析 我们可以维护一个前缀和 ...
- 5433. 【NOIP2017提高A组集训10.28】图
题目描述 Description 有一个n个点A+B条边的无向连通图,有一变量x,每条边的权值都是一个关于x的简单多项式,其中有A条边的权值是k+x,另外B条边的权值是k-x,如果只保留权值形如k+x ...
- 【JZOJ5439】【NOIP2017提高A组集训10.31】Calculate
题目 分析 对于\[\sum_{i=1}^{n}\lfloor\dfrac{T-B_i}{A_i}\rfloor\] 我们考虑拆开处理,得到 \[\sum_{i=1}^{n}(\lfloor\dfra ...
- 【JZOJ5430】【NOIP2017提高A组集训10.27】图
题目 有一个n个点的无向图,给出m条边,每条边的信息形如\(<x,y,c,r>\) 给出q组询问形如\(<u,v,l,r>\) 接下来解释询问以及边的意义 询问表示,一开始你在 ...
- 5432. 【NOIP2017提高A组集训10.28】三元组
题目 题目大意 给你\(X+Y+Z\)个三元组\((x_i,y_i,z_i)\). 然后选\(X\)个\(x_i\),选\(Y\)个\(y_i\),选\(Z\)个\(z_i\). 每个三元组只能选择其 ...
- 【JZOJ5434】【NOIP2017提高A组集训10.30】Matrix
题目 分析 假设答案为ans, 发现\[k=\sum_{i=1}^{min(n,k)}\lfloor \dfrac{ans}{i} \rfloor\] 于是可以对ans进行二分, 用分块来求出上面的式 ...
- 【NOIP2017提高A组集训10.21】Fantasy
题目 Y sera 陷入了沉睡,幻境中它梦到一个长度为N 的序列{Ai}. 对于这个序列的每一个子串,定义其幻境值为这个子串的和,现在Y sera 希望选择K 个不同的子串并使得这K 个子串的幻境值之 ...
- JZOJ 【NOIP2017提高A组模拟9.14】捕老鼠
JZOJ [NOIP2017提高A组模拟9.14]捕老鼠 题目 Description 为了加快社会主义现代化,建设新农村,农夫约(Farmer Jo)决定给农庄里的仓库灭灭鼠.于是,猫被农夫约派去捕 ...
- JZOJ 【NOIP2016提高A组集训第16场11.15】SJR的直线
JZOJ [NOIP2016提高A组集训第16场11.15]SJR的直线 题目 Description Input Output Sample Input 6 0 1 0 -5 3 0 -5 -2 2 ...
随机推荐
- 3.7:基于Weka的K-means聚类的算法示例
〇.目标 1.使用Weka平台,并在该平台使用数据导入.可视化等基本操作: 2.对K-means算法的不同初始k值进行比较,对比结果得出结论. 一.打开Weka3.8并导入数据 二.导入数据 三.Si ...
- 【SQL基础】【关键字大写】条件查询:比较、不等于、IN、为空、BETWEEN
〇.概述 1.内容介绍 条件查询:比较.不等于.IN.为空.BETWEEN 2.建表语句 drop table if exists user_profile; CREATE TABLE `user_p ...
- O-MVLL:支持ARM64的基于LLVM的代码混淆模块
O-MVLL介绍 O-MVLL的开发灵感来自于另一个著名的基于LLVM的代码混淆项目ollvm,并在其基础上做了创新和改进.O-MVLL的混淆逻辑实现方式也是通过LLVM Pass,支持也仅会支持AR ...
- 二阶段目标检测网络-FPN 详解
论文背景 引言(Introduction) 特征金字塔网络 FPN FPN网络建立 Anchor锚框生成规则 实验 代码解读 参考资料 本篇文章是论文阅读笔记和网络理解心得总结而来,部分资料和图参考论 ...
- Python 大数据量文本文件高效解析方案代码实现
大数据量文本文件高效解析方案代码实现 测试环境 Python 3.6.2 Win 10 内存 8G,CPU I5 1.6 GHz 背景描述 这个作品来源于一个日志解析工具的开发,这个开发过程中遇到的一 ...
- jmeter websocket 接口测试环境准备
1.下载jdk并进行安装配置环境 2.下载jmeter,解压可直接使用,无需安装 3.进入下载地址下载plugins-manager.jar 插件 4.将下载好plugins-manager.jar ...
- matlab狄拉克锥的三维图
石墨烯(graphene)中的狄拉克锥(Dirac cone)图形.直接按照能级公式绘图,公式参考[1]中 energy of the electrons 公式. %matlab代码 clear; g ...
- 洛谷P1605例题分析
迷宫 题目描述 给定一个 \(N \times M\) 方格的迷宫,迷宫里有 \(T\) 处障碍,障碍处不可通过. 在迷宫中移动有上下左右四种方式,每次只能移动一个方格.数据保证起点上没有障碍. 给定 ...
- 联邦学习(Federated Learning)
联邦学习的思想概括为:一种无需交换数据(只交换训练中间参数或结果)的分布式机器学习技术,在保护数据隐私的同时实现数据共享,解决数据孤岛问题. 本文仅介绍基本概念,详细请查看文末参考资料. 基本概念 联 ...
- react,vue中的key有什么作用?(key的内部原理)
1.虚拟DOM中的key的作用: key是虚拟dom对象的标识,当状态中的数据发生变化时,vue会根据新数据生成新的虚拟dom,随后vue进行新的虚拟dom与旧的虚拟dom的差异比较. 2.比较规则 ...