题意

原题来自: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)\)。

代码

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstdlib>
  4. #include<cmath>
  5. #include<set>
  6. #include<map>
  7. #include<queue>
  8. #include<stack>
  9. #include<algorithm>
  10. #include<bitset>
  11. #include<cassert>
  12. #include<ctime>
  13. #include<cstring>
  14. #define rg register
  15. #define il inline
  16. #define co const
  17. template<class T>il T read()
  18. {
  19. rg T data=0;
  20. rg int w=1;
  21. rg char ch=getchar();
  22. while(!isdigit(ch))
  23. {
  24. if(ch=='-')
  25. w=-1;
  26. ch=getchar();
  27. }
  28. while(isdigit(ch))
  29. {
  30. data=data*10+ch-'0';
  31. ch=getchar();
  32. }
  33. return data*w;
  34. }
  35. template<class T>T read(T&x)
  36. {
  37. return x=read<T>();
  38. }
  39. using namespace std;
  40. typedef long long ll;
  41. co int N=2e5+2;
  42. ll w[N],d[N];
  43. ll sum;
  44. int q[N];
  45. ll Up(int j,int k) // edit 1: long long for slope
  46. {
  47. return d[j]*w[j]-d[k]*w[k];
  48. }
  49. ll Down(int j,int k)
  50. {
  51. return w[j]-w[k];
  52. }
  53. ll Cal(int i,int j)
  54. {
  55. return sum-d[j]*w[j]-d[i]*(w[i]-w[j]);
  56. }
  57. int main()
  58. {
  59. // freopen("LG4360.in","r",stdin);
  60. // freopen(".out","w",stdout);
  61. int n=read<int>();
  62. for(int i=1;i<=n;++i)
  63. read(w[i]),read(d[i]);
  64. for(int i=n;i>=1;--i)
  65. d[i]+=d[i+1],sum+=w[i]*d[i];
  66. for(int i=1;i<=n;++i)
  67. w[i]+=w[i-1];
  68. int head=0,tail=0;
  69. q[tail++]=0;
  70. ll ans=sum;
  71. for(int i=1;i<=n;++i)
  72. {
  73. while(head+1<tail&&Up(q[head+1],q[head])>=d[i]*Down(q[head+1],q[head]))
  74. ++head;
  75. ans=min(ans,Cal(i,q[head]));
  76. 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]))
  77. --tail;
  78. q[tail++]=i;
  79. }
  80. printf("%lld\n",ans);
  81. return 0;
  82. }

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. resin服务一直不停重启

    resin服务不断重启. 原因为resin配置文件使用域名.需要到服务上绑定一下域名.

  2. windows 安装python3.5启动报错:api-ms-win-crt-runtime-l1-1-0.dll丢失

    下载: api-ms-win-crt-runtime就是MFC的运行时环境的库,python在windows上编译也是用微软的visual studio C++编译的,底层也会用到微软提供的C++库和 ...

  3. 实验四Android开发

    实验四Java Android简易开发 实验准备 Android Studio 的下载: Android Studio 安装教程 在安装过程中的问题: 在下载了官网上的说明包含sdk的安装包之后找不到 ...

  4. SQLite教程

    SQLite教程 http://www.runoob.com/sqlite/sqlite-date-time.html SQLite管理工具http://www.sqliteexpert.com/do ...

  5. spring配置mq入门案例

    第一步:添加maven配置 <!-- mq --> <dependency> <groupId>org.springframework</groupId> ...

  6. DNS解析过程和DNS挟持

    1.DNS解析过程详解 1).在浏览器中输入一个域名,例如www.tmall.com,操作系统会先检查自己本地的hosts文件是否有这个网址映射关系,如果有,就先调用这个IP地址映射,完成域名解析, ...

  7. Dispatcher initialization failedUnable to load configuration 解决办法

    检查<package name="action" extends="struts-default"></package>中是否有exte ...

  8. WebUploader 解决文件多次上传和删除上传文件的问题

    文件多次上传有两种情况: 1. 上传前的多次选择 2. 上传成功后,再次选择 其实API上,已经有了介绍了,不知道为什么有同学还是不知道如何做,我来抛砖引玉吧. 配置项: duplicate {Boo ...

  9. SQLServer行列转换PIVOT函数中聚合函数的使用意义及选择

    例子:https://blog.csdn.net/wikey_zhang/article/details/76849826 DECLARE @limitDay INT;SET @limitDay = ...

  10. DPDK在OpenStack中的实现

    随着云计算与大数据的快速发展,其对数据中心网络的性能和管理提出了更高的要求,但传统云计算架构存在多个I/O瓶颈,由于云平台基本上是采用传统的X86服务器加上虚拟化方式组建,随着40G.100G高速网卡 ...