【题解】[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 ...
随机推荐
- Android开发之设置应用设置全屏的两种解决方法 兼容android5.0等两种解决方法
在开发中我们经常需要把我们的应用设置为全屏,有两种方法,一中是在代码中设置,另一种方法是在配置文件里改! 一.在代码中设置: 代码如下: package com.android.tutor; imp ...
- 51,N皇后
from typing import List# 这道题还是比较经典的深搜递归调用的问题.# 只需要保证二维列表的每一行,每一列,每一对角线只有一个皇后就好了.class Solution: def ...
- Shader 的 Blend
Blend SrcAlpha OneMinusSrcAlpha //alpha blending Blend One OneMinusSrcAlpha //premultiplied alpha bl ...
- HTTP协议中的提交方式和解释POST、GET、HEAD、PUT等
最基本的方法有4种,分别是GET,POST,PUT,DELETE HTTP中的GET,POST,PUT,DELETE就对应着对这个资源的查,改,增,删4个操作 GET一般用于获取/查询资源信息,而PO ...
- 吐槽express 中间件multer
工作不是那么忙,想学一下Express+multer弄一个最简单的文件上传,然后开始npm install,然后开始对着multer官方文档一顿操作. 前台页面最简单的: <!DOCTYPE h ...
- jQuery 如何实现 模糊搜索
如何实现 模糊搜索 当我们浏览网页的时候,通常能看到搜索栏,这大大的提高了我们获取数据的目的性.那如何去实现一个简单的模糊搜索 框呢,以下案例获取能给你一点思路. 以下案例,可以实现当按键按下时,自动 ...
- Java判断一个字符串是否是回文
package com.spring.test; /** * 判断字符串是否为回文 * * @author liuwenlong * @create 2020-08-31 11:33:04 */ @S ...
- [剑指Offer]33-根据后序序列判断是否能组成BST
题目 如题. 题解 从序列第一个大于根节点的值往后都是右子树,判断右子树是否都大于根节点. 然后递归判断左右子树是否是BST 代码 class TreeNode { int val = 0; Tree ...
- [剑指Offer]61-扑克牌中的顺子
题目 "红心A,黑桃3,小王,大王,方片5",大\小 王可以看成任何数字,并且A看作1,J为11,Q为12,K为13.上面的5张牌就可以变成"1,2,3,4,5" ...
- 常见重构技巧 - 5种方式去除多余的if else
常见重构技巧 - 去除多余的if else 最为常见的是代码中使用很多的if/else,或者switch/case:如何重构呢?方法特别多,本文带你学习其中的技巧. 常见重构技巧 - 去除多余的if ...