「BZOJ2153」设计铁路 - 斜率DP
A省有一条东西向的公路经常堵车,为解决这一问题,省政府对此展开了调查。
调查后得知,这条公路两侧有很多村落,每个村落里都住着很多个信仰c教的教徒,每周日都会开着自家的车沿公路到B地去“膜拜”他们的教主,这便是堵车的原因。
详细调查显示:这里总共有N个村落,并且它们都在B地的东边。编号为i的村落住有Ri个信仰c教的教徒,距离B地的距离为Ti(单位:公里)。为解决这一问题,A省政府决定在这条公路下修建一条地下快速铁路来缓解交通,并沿线修建若干个车站(B地会修建终点站,不算车站)。
每名教徒都会先往B地方向开车(如果他所在村庄处恰好有车站就不必开车了),到最近的一个快速铁路车站时换乘(如果直接开到B地就不用换乘了),再通过快速铁路到B地。
但A政府遇到一个难题:修建多少个车站以及在哪修建车站。一个修建车站的方案中,如果修建过多的车站则会花费过多的钱,但修建的车站少了或者修建的位置不对又会导致公路的拥堵。
A政府为了协调这两方面,采用评分的方式来衡量一个方案的好坏(分数越大方案越坏):每修建一个车站会增加m的分数,在某一次“膜拜”中(只考虑去,不考虑返回),每导致1个教徒开车行驶1公里会增加1分。
现请你设计一个修建车站的方案,使得分数最小。请输出这个最小的分数。
解题报告
首先考虑贪心是否可做,如果只能选取一个点设置车站,不妨设这个点距离为 \(x\),花费总和就是 \(\sum_{i=1}^n (T_i \times R_i) + m - x \times \sum_{i=1}^n[T_i \ge x]\) ,前面部分是常数,而后面部分是一个无法确定有几个峰的函数,因此我们需要考虑动态规划或者模拟退火解决这个问题
由于模拟退火的玄学性,这里不做多的讨论,可以尝试 \(O(n*(退火复杂度))\) 进行依次退火,下面我们将用动态规划解决本题
我们不妨将 \(T_i\) 按照降序排序,我们将会有一个比较原始的区间DP:
我们用 \(f[i]\) 表示前 \(i\) 个村落建立若干车站的最小值,且 \(i\) 处有车站设立。则 :
\]
利用前缀和,我们令 \(sumT[i]\) 表示 \(R[i]*T[i]\) 的前缀和,\(sum[i]\) 表示 \(R[i]\) 的前缀和,则:
\]
此时这个问题可以在 \(O(n^2)\) 时间求解
观察这个式子,发现当 \(i\) 已经确定的时候 $f[i] = \min_{j \le i}{-sumT[j] + T_i * sum[j] + f[j]} + K $ 此处 \(K = m + sumT[i] - T_i * sum[i]\) 是一个常数,换句话说,我们只需要找出最小的 \(- sumT[j] + T_i * sum[j] + f[j]\) 即可
我们不妨考虑这样一条直线 \(y = - T_i * (x - sum[j]) + f[j] - sumT[j]\) 过点 \((sum[j], f[j] - sumT[j])\), 它的截距就是我们要求的 \(- sumT[j] + T_i * sum[j] + f[j]\) 要使截距最小,那直线就应该尽量往下移动。
我们可以发现我们选取的最优点应该是在一个下凸壳上的,由于 \(sum[j]\) 时单调的,我们可以用一个简单的单调队列进行维护。
此时复杂度降为了 \(O(n)\)
代码
#include <bits/stdc++.h>
#define T first
#define R second
typedef long long ll;
const int maxn = 40000 + 10;
int n, q[maxn];
ll m, s1[maxn], s2[maxn], f[maxn];
std::pair<ll, ll> p[maxn];
ll F(int i, int j) {
return f[j] + s1[i] - s1[j] - p[i].T * (s2[i] - s2[j]);
}
double slope(int i, int j) {
double x1 = s2[i], y1 = f[i] - s1[i];
double x2 = s2[j], y2 = f[j] - s1[j];
return (y2 - y1) / (x2 - x1);
}
int main() {
scanf("%d %lld", &n, &m);
for (int i = 1; i <= n; ++ i) {
scanf("%d %d", &p[i].T, &p[i].R);
}
std::sort(p + 1, p + n + 1); std::reverse(p + 1, p + n + 1); p[++n] = std::make_pair(0, 0);
for (int i = 1; i <= n; ++ i) {
s1[i] = s1[i - 1] + p[i].T * p[i].R;
s2[i] = s2[i - 1] + p[i].R;
}
int head = 1, tail = 1; q[1] = 0;
for (int i = 1; i <= n; ++ i) {
while (head < tail && F(i, q[head]) >= F(i, q[head + 1])) head ++;
f[i] = F(i, q[head]); if (i != n) f[i] += m;
while (head < tail && slope(i, q[tail]) < slope(i, q[tail - 1])) tail --;
q[++tail] = i;
}
printf("%lld", f[n]);
}
「BZOJ2153」设计铁路 - 斜率DP的更多相关文章
- 「USACO16OPEN」「LuoguP3147」262144(区间dp
P3147 [USACO16OPEN]262144 题目描述 Bessie likes downloading games to play on her cell phone, even though ...
- loj#2483. 「CEOI2017」Building Bridges 斜率优化 cdq分治
loj#2483. 「CEOI2017」Building Bridges 链接 https://loj.ac/problem/2483 思路 \[f[i]=f[j]+(h[i]-h[j])^2+(su ...
- LOJ2316. 「NOIP2017」逛公园【DP】【最短路】【思维】
LINK 思路 因为我想到的根本不是网上的普遍做法 所以常数出奇的大,而且做法极其暴力 可以形容是带优化的大模拟 进入正题: 首先一个很显然的思路是如果在合法的路径网络里面存在零环是有无数组解的 然后 ...
- 「LOJ2091」「ZJOI2016」小星星 容斥+DP
题目描述 小 Y 是一个心灵手巧的女孩子,她喜欢手工制作一些小饰品.她有\(n\)颗小星星,用 \(m\)条彩色的细线串了起来,每条细线连着两颗小星星.有一天她发现,她的饰品被破坏了,很多细线都被拆掉 ...
- loj2318 「NOIP2017」宝藏[状压DP]
附带其他做法参考:随机化(模拟退火.爬山等等等)配合搜索剪枝食用. 首先题意相当于在图上找一颗生成树并确定根,使得每个点与父亲的连边的权乘以各自深度的总和最小.即$\sum\limits_{i}dep ...
- LOJ 2550 「JSOI2018」机器人——找规律+DP
题目:https://loj.ac/problem/2550 只会写20分的搜索…… #include<cstdio> #include<cstring> #include&l ...
- LOJ 2546 「JSOI2018」潜入行动——树形DP
题目:https://loj.ac/problem/2546 dp[ i ][ j ][ 0/1 ][ 0/1 ] 表示 i 子树,用 j 个点,是否用 i , i 是否被覆盖. 注意 s1<= ...
- 「LuoguP2365」 任务安排(dp
题目描述 N个任务排成一个序列在一台机器上等待完成(顺序不得改变),这N个任务被分成若干批,每批包含相邻的若干任务.从时刻0开始,这些任务被分批加工,第i个任务单独完成所需的时间是Ti. 在每批任务开 ...
- 「IOI1998」「LuoguP4342」Polygon(区间dp
P4342 [IOI1998]Polygon - 洛谷 题意翻译 题目可能有些许修改,但大意一致 多边形是一个玩家在一个有n个顶点的多边形上的游戏,如图所示,其中n=4.每个顶点用整数标记,每个边用符 ...
随机推荐
- java 泛型E T ?的区别
Java泛型中的标记符含义: E - Element (在集合中使用,因为集合中存放的是元素) T - Type(Java 类) K - Key(键) V - Value(值) N - Number ...
- linux常用命令:mv 命令
mv命令是move的缩写,可以用来移动文件或者将文件改名(move (rename) files),是Linux系统下常用的命令,经常用来备份文件或者目录. 1.命令格式: mv [选项] 源文件或目 ...
- 【javascript】获取 格式化时间
function getDate() { var myDate = new Date(); var month = myDate.getMonth() + 1; var day = myDate.ge ...
- vue中组件通信之子父通信
<div id="app"> <parent-comp1></parent-comp1> <parent-comp1></pa ...
- jumpserver堡垒机安装
1. 下载jumpserver cd /opt wget https://github.com/jumpserver/jumpserver/archive/master.zip unzip maste ...
- mergesort_arithmetic_python
def merge(a, b): c = [] h = j = 0 while j < len(a) and h < len(b): if a[j] < b[h]: c.append ...
- 使用Holer远程桌面登录家里电脑和公司内网电脑
1. Holer工具简介 Holer exposes local servers behind NATs and firewalls to the public internet over secur ...
- 海瑞菌的web前端学习直播间
这是本人的web前端学习直播间 一般每天晚上10点--12点为直播时间...以web前端开发为主. 若设备无法打开,请点击链接进入:https://www.huya.com/14958154 setT ...
- lnmp重置密码
wget http://soft.vpser.NET/lnmp/ext/reset_mysql_root_password.sh;sh reset_mysql_root_password.sh
- php使用phpexcel导出文件
php使用phpexcel导出文件 首先需要去官网https://github.com/PHPOffice/PHPExcel/下载PHPExcel 代码如下: <?php date_defaul ...