【题解】[CEOI2004]锯木厂选址
\(\text{Solution:}\)
注意到题目中的编号是倒着的,于是我们的距离要预处理的是后缀和。
考虑如何\(n^2\)搞:
设\(dp[i]\)表示选择\(i\)为第二个中转点的最小代价。
枚举在\(i\)前面的\(j\),代价就是\(dp[i]=\min_{j<i}All-dis[j]*sum[j]-dis[i]*(sum[i]-sum[j])\)
\(All\)是所有树木运输到\(1\)号点的代价。可以理解为,有一部分运输到\(j\)就不用运了,于是把这部分减掉。\(sum\)是重量的前缀和。
枚举前一个点,显然是\(n^2\)的(虽然这样可以过)
考虑优化,先推柿子(令\(S=All\)):
\]
\]
\]
这时,令:\(y=dis[j]*sum[j],k=dis[i],x=sum[j],b=(S-dp[i]-dis[i]*sum[i])\),一个一次函数式出来了。
显然的斜率优化,但是这里有一个坑,害得我看博客又理解了半天……
其实,如果按照最小化截距来写,会发现这就是一个下凸壳,即使\(dis[i]\)是递减而非递增。但是看了题解后发现,维护的是一个上凸壳。
为什么?
考虑我们究竟要最小化还是最大化。
如果最小化\(b=(S-dp[i]-dis[i]*sum[i])\),则因为\(dp[i]\)前面的符号是负的,所以我们就反其道而行之地把它给最大化了。于是\(\text{Wrong Answer.}\)
所以,实际上我们要最大化截距\(b\),从而最小化\(dp[i]\).
于是我们的任务就变成维护一个上凸包了。观察到\(dis[i]\)递减,于是我们只保留小于\(dis[i]\)的线段。因为后面的最优线段一定是斜率递减的。
我们通过上述分析,可以通过单调队列优化到\(O(n).\)
这题的主要价值在于,注意\(b\)的符号,不是题目中要求\(min\)就一定是下凸包,也不是题目中求最大值就一定是下凸包。看截距的时候要特别留意\(dp[i]\)——我们最关心的值的符号,以此来确定维护上凸壳还是下凸壳。
#include<bits/stdc++.h>
using namespace std;
int n,w[200010],d[200010];
int s[200010],sum[200010];
int dp[200010],ans=0;
int head,tail,q[200010];
int dis[200010],S,A=2147483647;
int Y(int x){return dis[x]*sum[x];}
int X(int x){return sum[x];}
double slope(int x,int y){return (Y(y)-Y(x))/(X(y)-X(x));}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;++i)scanf("%d%d",&w[i],&dis[i]);
for(int i=n;i>=1;--i)dis[i]+=dis[i+1];
for(int i=1;i<=n;++i)ans+=dis[i]*w[i];
for(int i=1;i<=n;++i)sum[i]=sum[i-1]+w[i];
//Dis[i]>(dis[k]*sum[k]-dis[j]*sum[j])/(sum[k]-sum[j])
//Dp[i]=S-dis[j]*sum[j]-dis[i]*(sum[i]-sum[j])
//Dis[j]*sum[j]=dis[i]*sum[j]+(S-dp[i]-dis[i]*sum[i])
//最小化后面一坨 斜率是dis[i]
//head=tail=1;q[head]=1;
//cout<<ans<<endl;
for(int i=1;i<=n;++i){
while(head<tail&&slope(q[head],q[head+1])>=dis[i])head++;
dp[i]=ans-dis[q[head]]*sum[q[head]]-dis[i]*(sum[i]-sum[q[head]]);
//cout<<dp[i]<<" ";
A=min(A,dp[i]);
while(head<tail&&slope(q[tail-1],q[tail])<=slope(q[tail-1],i))--tail;
q[++tail]=i;
}
printf("%d\n",A);
return 0;
}
【题解】[CEOI2004]锯木厂选址的更多相关文章
- luoguP4360 [CEOI2004]锯木厂选址
题目链接 luoguP4360 [CEOI2004]锯木厂选址 题解 dis:后缀和 sum:前缀和 补集转化,减去少走的,得到转移方程 dp[i] = min(tot - sumj * disj - ...
- P4360 [CEOI2004]锯木厂选址
P4360 [CEOI2004]锯木厂选址 这™连dp都不是 \(f_i\)表示第二个锯木厂设在\(i\)的最小代价 枚举1号锯木厂 \(f_i=min_{0<=j<i}(\sum_{i= ...
- 动态规划(斜率优化):[CEOI2004]锯木厂选址
锯木场选址(CEOI2004) 从山顶上到山底下沿着一条直线种植了n棵老树.当地的政府决定把他们砍下来.为了不浪费任何一棵木材,树被砍倒后要运送到锯木厂. 木材只能按照一个方向运输:朝山下运.山脚下有 ...
- [BZOJ2684][CEOI2004]锯木厂选址
BZOJ权限题! Description 从山顶上到山底下沿着一条直线种植了n棵老树.当地的政府决定把他们砍下来.为了不浪费任何一棵木材,树被砍倒后要运送到锯木厂. 木材只能按照一个方向运输:朝山下运 ...
- LG4360 [CEOI2004]锯木厂选址
题意 原题来自:CEOI 2004 从山顶上到山底下沿着一条直线种植了 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]$表示将第二个锯 ...
- 【文文殿下】[CEOI2004]锯木厂选址 题解
题解 我们枚举建厂的位置,发现有个\(n^2\)的DP.随手搞个斜率优化到\(O(n)\). #include<bits/stdc++.h> using namespace std; ty ...
随机推荐
- 使用kind快速创建本地集群
简 介 kind是另一个Kubernetes SIG项目,但它与minikube有很大区别.它可以将集群迁移到Docker容器中,这与生成虚拟机相比,启动速度大大加快.简而言之,kind是一个使用Do ...
- 面试【JAVA基础】集合类
1.ArrayList的扩容机制 每次扩容是原来容量的1.5倍,通过移位的方法实现. 使用copyOf的方式进行扩容. 扩容算法是首先获取到扩容前容器的大小.然后通过oldCapacity (oldC ...
- 为系统增加删除swap空间
增加 1.创建/home/swap这么一个分区文件.文件大小是512000个block,一般情况下1个block为1k,所以这里空间是512M,这个空间大小自己随意定义. dd if=/dev/zer ...
- centos7图形化安装oracle11g
#设置主机名 hostnamectl set-hostname oracle #yum安装 yum -y install unzip vim* bash-completion bash-complet ...
- 【翻译】.NET 5 RC1发布
9月14日,.NET5发布了(Release Candidate)RC1版本,RC的意思是指我们可以进行使用,并且RC版本得到了支持,该版本是.NET5.0的最终版本,也是11月正式版本之前两个RC版 ...
- CTF-BugKu-加密
2020.09.12 恕我直言,上午做WeChall那个做自闭了,下午复习一下之前做过的. 做题 第一题 滴答~滴 https://ctf.bugku.com/challenges#滴答~滴 摩斯密码 ...
- [Binder深入学习二]Binder驱动——基础数据结构二
Userspace和KernelSpace进行交互时,大部分命令是通过 ioctl 实现的,在这个过程中,最重要的一个便是 BINDER_WRITE_READ 命令了. #define BINDER_ ...
- 基于Socket的编程
2020/7/5 客户端步骤: 1.创建Socket. 根据指定服务端的IP地址或者端口号构造Socket类对象: Socket socket = new Socket(InetAddress. ...
- k8s运行容器之Job(四)
Job 容器按照持续运行的时间可分为两类:服务类容器和工作类容器. 服务类容器通常持续提供服务,需要一直运行,比如 http server,daemon 等.工作类容器则是一次性任务,比如批处理程序, ...
- Hive 窗口函数sum() over()求当前行和前面n条数据的和
前几天遇到一个这样的需求:销售总占比加起来超过75%的top分类.具体需求是这样的:商品一级分类标签下面有许多商品标签,例如运动户外一级标签,下面可能存在361°,CBA,Nike,Adidas... ...