题意

原题来自: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. HTML5相册浏览插件

    在线演示 本地下载

  2. Google揭露SHA-1碰撞,加速数据重删字节对比

    原创 架构师技术联盟  近期,Google和道荷兰阿姆斯特研究者宣布攻破了世界上第一例公开的SHA-1哈希碰撞实例,业界一片哗然.当两组不同的数据(文件.一段数据)计算出相同的Hash值时,即视为二者 ...

  3. RN app打包

    最近使用React Native做起了移动应用,之前做过一点react,有一点react基础,后来听说RN还不错,就做起了RN项目.为了让辛辛苦苦开发的项目想在手机端运行,就涉及到发布打包. 防止自己 ...

  4. 迁移cnblog博客

    title: 迁移cnblog博客 date: 2018-03-18 categories: cnblogs tags: life 写博客最怕就是这种迁来迁去的,太麻烦了 还好老早就使用markdow ...

  5. [LnOI2019]加特林轮盘赌(DP,概率期望)

    [LnOI2019]加特林轮盘赌(DP,概率期望) 题目链接 题解: 首先特判掉\(p=0/1\)的情况... 先考虑如果\(k=1\)怎么做到\(n^2\)的时间复杂度 设\(f[i]\)表示有\( ...

  6. LeetCode——Keyboard Row

    LeetCode--Keyboard Row Question Given a List of words, return the words that can be typed using lett ...

  7. tomcat_下载

    1. http://tomcat.apache.org/ 2. 3.

  8. [Jquery 插件]活动倒计时,可同步服务器时间,倒计时格式随意设置

    活动倒计时,可同步服务器时间,倒计时格式随意设置 使用说明 /* #活动倒计时,可同步服务器时间 startTime:起始时间 endTime:结束时间 format_str:字符模板 speed:倒 ...

  9. LeetCode第[42]题(Java):Trapping Rain Water (数组方块盛水)——HARD

    题目:接雨水 难度:hard 题目内容: Given n non-negative integers representing an elevation map where the width of ...

  10. LeetCode第[21][23]题(Java):Merge Sorted Lists

    题目:合并两个已排序链表 难度:Easy 题目内容: Merge two sorted linked lists and return it as a new list. The new list s ...