题意

原题来自: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}\)。有三种情况

  1. \[
    k_{i,j}<k_{j,k}<dis
    \]
    那么\(i\)比\(j\)优,\(j\)比\(k\)优。
  2. \[
    k_{i,j}<dis<k_{j,k}
    \]
    那么\(i\)比\(j\)优,\(k\)比\(j\)优。
  3. \[
    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]锯木厂选址的更多相关文章

  1. P4360 [CEOI2004]锯木厂选址

    P4360 [CEOI2004]锯木厂选址 这™连dp都不是 \(f_i\)表示第二个锯木厂设在\(i\)的最小代价 枚举1号锯木厂 \(f_i=min_{0<=j<i}(\sum_{i= ...

  2. luoguP4360 [CEOI2004]锯木厂选址

    题目链接 luoguP4360 [CEOI2004]锯木厂选址 题解 dis:后缀和 sum:前缀和 补集转化,减去少走的,得到转移方程 dp[i] = min(tot - sumj * disj - ...

  3. 动态规划(斜率优化):[CEOI2004]锯木厂选址

    锯木场选址(CEOI2004) 从山顶上到山底下沿着一条直线种植了n棵老树.当地的政府决定把他们砍下来.为了不浪费任何一棵木材,树被砍倒后要运送到锯木厂. 木材只能按照一个方向运输:朝山下运.山脚下有 ...

  4. [BZOJ2684][CEOI2004]锯木厂选址

    BZOJ权限题! Description 从山顶上到山底下沿着一条直线种植了n棵老树.当地的政府决定把他们砍下来.为了不浪费任何一棵木材,树被砍倒后要运送到锯木厂. 木材只能按照一个方向运输:朝山下运 ...

  5. cogs 362. [CEOI2004]锯木厂选址

    ★★★   输入文件:two.in   输出文件:two.out   简单对比 时间限制:0.1 s   内存限制:32 MB 从山顶上到山底下沿着一条直线种植了n棵老树.当地的政府决定把他们砍下来. ...

  6. 2018.08.28 洛谷P4360 [CEOI2004]锯木厂选址(斜率优化dp)

    传送门 一道斜率优化dp入门题. 是这样的没错... 我们用dis[i]表示i到第三个锯木厂的距离,sum[i]表示前i棵树的总重量,w[i]为第i棵树的重量,于是发现如果令第一个锯木厂地址为i,第二 ...

  7. 洛谷P4360 [CEOI2004]锯木厂选址(斜率优化)

    传送门 我可能根本就没有学过斜率优化…… 我们设$dis[i]$表示第$i$棵树到山脚的距离,$sum[i]$表示$w$的前缀和,$tot$表示所有树运到山脚所需要的花费,$dp[i]$表示将第二个锯 ...

  8. luogu P4360 [CEOI2004]锯木厂选址

    斜率优化dp板子题[迫真] 这里从下往上标记\(1-n\)号点 记\(a_i\)表示前缀\(i\)里面树木的总重量,\(l_i\)表示\(i\)到最下面的距离,\(s_i\)表示\(1\)到\(i-1 ...

  9. [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的代价) ...

随机推荐

  1. 基于Bootstrap的日历控件和日期选择插件

    在线演示 本地下载

  2. CentOS限制SSH登录地址

    编辑hosts.allow文件,将允许连接的地址写进去 [root@Elements ~]# vim /etc/hosts.allow sshd:10.10.10.1:allow sshd:172.1 ...

  3. Cnblog页面美化小记

    Cnblog页面美化小记 这两天我在网上翻找了许许多多的资料,打开了不计其数的博客,对着\(js\).\(html\).\(css\)等文件删删改改,在浏览器和\(vscode\)间辗转腾挪...总算 ...

  4. Linux 通过进程Pid与端口互查

    ps -aux 状态详解 https://blog.csdn.net/whatday/article/details/54409387. linux下通过进程名查看其占用端口: https://www ...

  5. RQN 273 马棚问题 dp

    PID273 / 马棚问题  2016-07-29 18:21:55 运行耗时:1624 ms 运行内存:16248 KB 题目描述 每天,小明和他的马外出,然后他们一边跑一边玩耍.当他们结束的时候, ...

  6. js插件封装

    插件封装原则 1.暴露出来的实例必须只能是一个 2.IIFE包裹 !执行包裹 函数作用域保护 3.实例化方法不要写在函数内 throw这个方法是报错

  7. 如何在深层嵌套ngRepeat中获取不同层级的$index

    <ul class="list-group" ng-repeat="item in vm.appData" ng-init="outerInde ...

  8. [日常训练]AekdyCoin的跳棋

    Description $AekdyCoin$正在玩一个游戏,该游戏要用到两副牌和一个数轴和一个棋子. 刚开始的时候棋子位于数轴的$0$位置.然后$AekdyCoin$交替的从两副牌中抽取一张牌,然后 ...

  9. jQuery EasyUI Datagrid VirtualScrollView视图简单分析

    大家都知道EasyUI的Datagrid组件在加载大数据量时的优势并不是很明显,相对于其他一些框架,如果数据量达到几千,便会比较慢,特别是在IE下面.针对这种情况,我们首要做的是要相办法优化datag ...

  10. Ant Design

    https://ant.design/components/form-cn/    (Ant Design of React 中文网) 1.Ant Design of react (相关资料) htt ...