LG4360 [CEOI2004]锯木厂选址
题意
原题来自:CEOI 2004
从山顶上到山底下沿着一条直线种植了 n 棵老树。当地的政府决定把他们砍下来。为了不浪费任何一棵木材,树被砍倒后要运送到锯木厂。
木材只能朝山下运。山脚下有一个锯木厂。另外两个锯木厂将新修建在山路上。你必须决定在哪里修建这两个锯木厂,使得运输的费用总和最小。假定运输每公斤木材每米需要一分钱。
你的任务是编写一个程序,读入树的个数和他们的重量与位置,计算最小运输费用。
\(n \leq 2 \times 10^5\)
分析
参照TimeTraveller的题解。这题是斜率优化,不过算不上dp。
我们先写出朴素的DP方程式:
\[
dp[i]=\min\{ totsum-dis[j]*sum[j]-dis[i]*(sum[i]-sum[j]) \}(j<i)
\]
其中\(dp[i]\)表示当前第二个工厂修到第ii棵树的位置时的最小花费,\(totsum\)表示所有树一开始全部运送的山脚下的花费,\(dis[i]\)表示距离的后缀和(因为我们是从上运到下面),\(sum[i]\)表示树的重量的前缀和。那么在\(i,j\)处修了工厂后花费就变成了总花费\(totsum\)减去从\(j\)厂运到山脚的额外花费\(dis[j]*sum[j]\),再减去从\(i\)厂运到山脚下的额外花费\(dis[i]∗(sum[i]−sum[j])\)。
形象的说,就是你先把\(j\)前面的木材运到\(j\)厂,然后减去这些木材运到山脚的花费,再把\(i,j\)之间的木材运到\(i\)厂,再减去它们到山脚的花费。
然后我们将DP方程式变形,令\(j,k(j<k)\)这两种决策转移到\(i\)的时候,\(k\)决策更优秀,那么就可以得到
\[
totsum-dis[j]*sum[j]-dis[i]*(sum[i]-sum[j])>totsum-dis[k]*sum[k]-dis[i]*(sum[i]-sum[k])
\]
整理后可以得出:
\[
\frac{dis[j]*sum[j]-dis[k]*sum[k]}{sum[j]-sum[k]}>dis[i]
\]
然后根据\(>\)号,对非上凸的情况分类讨论可以得出要维护上凸包。讨论过程如下:
首先假设有不上凸的连续\(i,j,k\)三个点,\(k_{i,j}<k_{j,k}\)。有三种情况
- \[
k_{i,j}<k_{j,k}<dis
\]
那么\(i\)比\(j\)优,\(j\)比\(k\)优。 - \[
k_{i,j}<dis<k_{j,k}
\]
那么\(i\)比\(j\)优,\(k\)比\(j\)优。 - \[
dis<k_{i,j}<k_{j,k}
\]
那么\(j\)比\(i\)优,\(k\)比\(j\)优。
综上,\(j\)是无用的点。所以要维护上凸性,就是上凸包。
至此,得出一般结论:
- 若斜率式后的符号是\(>\),则维护上凸包。
- 若斜率式后的符号是\(<\),则维护下凸包。
然后由于\(dis[i]\)单调递减,所以可以用单调队列优化。
时间复杂度\(O(n)\)。
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<algorithm>
#include<bitset>
#include<cassert>
#include<ctime>
#include<cstring>
#define rg register
#define il inline
#define co const
template<class T>il T read()
{
rg T data=0;
rg int w=1;
rg char ch=getchar();
while(!isdigit(ch))
{
if(ch=='-')
w=-1;
ch=getchar();
}
while(isdigit(ch))
{
data=data*10+ch-'0';
ch=getchar();
}
return data*w;
}
template<class T>T read(T&x)
{
return x=read<T>();
}
using namespace std;
typedef long long ll;
co int N=2e5+2;
ll w[N],d[N];
ll sum;
int q[N];
ll Up(int j,int k) // edit 1: long long for slope
{
return d[j]*w[j]-d[k]*w[k];
}
ll Down(int j,int k)
{
return w[j]-w[k];
}
ll Cal(int i,int j)
{
return sum-d[j]*w[j]-d[i]*(w[i]-w[j]);
}
int main()
{
// freopen("LG4360.in","r",stdin);
// freopen(".out","w",stdout);
int n=read<int>();
for(int i=1;i<=n;++i)
read(w[i]),read(d[i]);
for(int i=n;i>=1;--i)
d[i]+=d[i+1],sum+=w[i]*d[i];
for(int i=1;i<=n;++i)
w[i]+=w[i-1];
int head=0,tail=0;
q[tail++]=0;
ll ans=sum;
for(int i=1;i<=n;++i)
{
while(head+1<tail&&Up(q[head+1],q[head])>=d[i]*Down(q[head+1],q[head]))
++head;
ans=min(ans,Cal(i,q[head]));
while(head+1<tail&&Up(i,q[tail-1])*Down(q[tail-1],q[tail-2])>=Up(q[tail-1],q[tail-2])*Down(i,q[tail-1]))
--tail;
q[tail++]=i;
}
printf("%lld\n",ans);
return 0;
}
LG4360 [CEOI2004]锯木厂选址的更多相关文章
- P4360 [CEOI2004]锯木厂选址
P4360 [CEOI2004]锯木厂选址 这™连dp都不是 \(f_i\)表示第二个锯木厂设在\(i\)的最小代价 枚举1号锯木厂 \(f_i=min_{0<=j<i}(\sum_{i= ...
- luoguP4360 [CEOI2004]锯木厂选址
题目链接 luoguP4360 [CEOI2004]锯木厂选址 题解 dis:后缀和 sum:前缀和 补集转化,减去少走的,得到转移方程 dp[i] = min(tot - sumj * disj - ...
- 动态规划(斜率优化):[CEOI2004]锯木厂选址
锯木场选址(CEOI2004) 从山顶上到山底下沿着一条直线种植了n棵老树.当地的政府决定把他们砍下来.为了不浪费任何一棵木材,树被砍倒后要运送到锯木厂. 木材只能按照一个方向运输:朝山下运.山脚下有 ...
- [BZOJ2684][CEOI2004]锯木厂选址
BZOJ权限题! Description 从山顶上到山底下沿着一条直线种植了n棵老树.当地的政府决定把他们砍下来.为了不浪费任何一棵木材,树被砍倒后要运送到锯木厂. 木材只能按照一个方向运输:朝山下运 ...
- cogs 362. [CEOI2004]锯木厂选址
★★★ 输入文件:two.in 输出文件:two.out 简单对比 时间限制:0.1 s 内存限制:32 MB 从山顶上到山底下沿着一条直线种植了n棵老树.当地的政府决定把他们砍下来. ...
- 2018.08.28 洛谷P4360 [CEOI2004]锯木厂选址(斜率优化dp)
传送门 一道斜率优化dp入门题. 是这样的没错... 我们用dis[i]表示i到第三个锯木厂的距离,sum[i]表示前i棵树的总重量,w[i]为第i棵树的重量,于是发现如果令第一个锯木厂地址为i,第二 ...
- 洛谷P4360 [CEOI2004]锯木厂选址(斜率优化)
传送门 我可能根本就没有学过斜率优化…… 我们设$dis[i]$表示第$i$棵树到山脚的距离,$sum[i]$表示$w$的前缀和,$tot$表示所有树运到山脚所需要的花费,$dp[i]$表示将第二个锯 ...
- luogu P4360 [CEOI2004]锯木厂选址
斜率优化dp板子题[迫真] 这里从下往上标记\(1-n\)号点 记\(a_i\)表示前缀\(i\)里面树木的总重量,\(l_i\)表示\(i\)到最下面的距离,\(s_i\)表示\(1\)到\(i-1 ...
- [CEOI2004]锯木厂选址 斜率优化DP
斜率优化DP 先考虑朴素DP方程, f[i][k]代表第k个厂建在i棵树那里的最小代价,最后答案为f[n+1][3]; f[i][k]=min(f[j][k-1] + 把j+1~i的树都运到i的代价) ...
随机推荐
- 基于Bootstrap的日历控件和日期选择插件
在线演示 本地下载
- CentOS限制SSH登录地址
编辑hosts.allow文件,将允许连接的地址写进去 [root@Elements ~]# vim /etc/hosts.allow sshd:10.10.10.1:allow sshd:172.1 ...
- Cnblog页面美化小记
Cnblog页面美化小记 这两天我在网上翻找了许许多多的资料,打开了不计其数的博客,对着\(js\).\(html\).\(css\)等文件删删改改,在浏览器和\(vscode\)间辗转腾挪...总算 ...
- Linux 通过进程Pid与端口互查
ps -aux 状态详解 https://blog.csdn.net/whatday/article/details/54409387. linux下通过进程名查看其占用端口: https://www ...
- RQN 273 马棚问题 dp
PID273 / 马棚问题 2016-07-29 18:21:55 运行耗时:1624 ms 运行内存:16248 KB 题目描述 每天,小明和他的马外出,然后他们一边跑一边玩耍.当他们结束的时候, ...
- js插件封装
插件封装原则 1.暴露出来的实例必须只能是一个 2.IIFE包裹 !执行包裹 函数作用域保护 3.实例化方法不要写在函数内 throw这个方法是报错
- 如何在深层嵌套ngRepeat中获取不同层级的$index
<ul class="list-group" ng-repeat="item in vm.appData" ng-init="outerInde ...
- [日常训练]AekdyCoin的跳棋
Description $AekdyCoin$正在玩一个游戏,该游戏要用到两副牌和一个数轴和一个棋子. 刚开始的时候棋子位于数轴的$0$位置.然后$AekdyCoin$交替的从两副牌中抽取一张牌,然后 ...
- jQuery EasyUI Datagrid VirtualScrollView视图简单分析
大家都知道EasyUI的Datagrid组件在加载大数据量时的优势并不是很明显,相对于其他一些框架,如果数据量达到几千,便会比较慢,特别是在IE下面.针对这种情况,我们首要做的是要相办法优化datag ...
- Ant Design
https://ant.design/components/form-cn/ (Ant Design of React 中文网) 1.Ant Design of react (相关资料) htt ...