前言

本来挺简单的一道题...

我发现自己不太擅长简化、抽象模型,老是不知道怎么把学过的技巧用上去_(:зゝ∠)_

题目

Kalila and Dimna are two jackals living in a huge jungle. One day they decided to join a logging factory in order to make money.

The manager of logging factory wants them to go to the jungle and cut n trees with heights a1, a2, ..., an. They bought a chain saw from a shop. Each time they use the chain saw on the tree number i, they can decrease the height of this tree by one unit. Each time that Kalila and Dimna use the chain saw, they need to recharge it. Cost of charging depends on the id of the trees which have been cut completely (a tree is cut completely if its height equal to 0). If the maximum id of a tree which has been cut completely is i (the tree that have height ai in the beginning), then the cost of charging the chain saw would be bi. If no tree is cut completely, Kalila and Dimna cannot charge the chain saw. The chainsaw is charged in the beginning. We know that for each i < j, ai < aj and bi > bj and also bn = 0 and a1 = 1. Kalila and Dimna want to cut all the trees completely, with minimum cost.

They want you to help them! Will you?

Input

The first line of input contains an integer n (1 ≤ n ≤ 105). The second line of input contains n integers a1, a2, ..., an (1 ≤ ai ≤ 109). The third line of input contains n integers b1, b2, ..., bn (0 ≤ bi ≤ 109).

It's guaranteed that a1 = 1, bn = 0, a1 < a2 < ... < an and b1 > b2 > ... > bn.

Output

The only line of output must contain the minimum cost of cutting all the trees completely.

Please, do not write the %lld specifier to read or write 64-bit integers in С++. It is preferred to use the cin, cout streams or the %I64d specifier.

Examples

Input

5
1 2 3 4 5
5 4 3 2 0

Output

25

Input

6
1 2 3 10 20 30
6 5 4 3 2 0

Output

138

题目大意

伐木工人用电锯伐木,一共需要砍n棵树,每棵树的高度为a[i],每次砍伐只能砍1单位高度,之后需要对电锯进行充电,费用为当前砍掉的树中最大id的b[id]值

a[1] = 1 , b[n] = 0,a[i]<a[i+1],b[i]>b[i+1]

问砍完所有的树的最小费用

分析

参考博客&特别鸣谢:

https://www.cnblogs.com/yejinru/p/3348326.html

https://blog.csdn.net/lerenceray/article/details/9365947

首先,由于b[n] = 0 , 所以很容易弄出一个O(n^2)的状态转移方程:

dp[1]=0;
for(int i=2;i<=n;i++)
{dp[i]=INF;for(int j=1;j<i;j++)dp[i]=min(dp[i],dp[j]+b[j]*a[i]);
}

这种朴素的转移方程显然会TLE

注意到以上的方程,其实就是1D1D模型(具体百度),可以利用斜率进行优化

题意大致是砍树,不一定按顺序砍,目的是为了使充电费用最低,看完标号最大的树,充电就不再需要费用,所以关键在于求砍完标号最大的树所需要的最小花费

DP优化,记dp[ i ]为砍倒第i棵树所需要的最小花费,

所以所以对于dp[ n ], dp[ n ] = min{ dp[ j ] + b[ j ] * a[ n ] }, j = 1, 2, 3, ...... n - 1

注意这里题目条件单调的,这可以作为斜率DP的一个标志


分析DP的具体操作:

设现在要求dp[ k ],在k之前的任意两个数,我们设为i, j, 且i < j < k

那么dp[ j ] + b[ j ] * a[ k ] 和 dp[ i ] + b[ i ] * a[ k ]两个方案那个更优呢?

作差比较, 移项化简得:如果 (dp[ j ] - dp[ i ]) / (b[ i ] - b[ j ]) < a[ k ] 则 方案 j 优于方案 i(这里要注意b[  ]递减,移项变号),

我们把左边看作一个两点的斜率,得到一个函数G(j, i)如果G(j, i)< a[ k ] 则 j 优于 i,可以删除 i 方案,且以后 j 之后再有其他数,i 也不可能成为最优方案,因为 j 比 i 优

另外 当G(j, i) < G ( k , j )时, 可以删除 j 方案,因为这样 j 永远不会是最优方案, 以上两步优化维护了一个单调队列, 图形上看相邻两点的斜率单调递增或递减,所以叫斜率DP优化吧?

原来复杂度n*n的降为了O(n),因为每个方案之进入队列一次,被提出以后不再加入

简单来说:

斜率优化无非是:假设j<k,有以下关系:

dp[ k ]+b[ k ] * a[ i ] < dp[ j ]+b[ j ]*a[ i ]

由于b[ k ]<b[ j ]

因此移项之后为:

( dp[ k ] - dp[ j ] ) / ( b[ j ] - b[ k ] ) < a[ i ]

因此,我们可以根据斜率进行优化,具体可以看代码,这部分比较好懂

Ps.可是为什么head=1,tail=2才可以呢...又是区间开闭的问题吗...?

代码

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int MAXN=1e5;
ll a[MAXN+5],b[MAXN+5],que[MAXN+5],dp[MAXN+5];
ll n;
ll f1(ll x,ll y)
{return dp[que[x]]-dp[que[y]];
}
ll f2(ll x,ll y)
{return b[que[x]]-b[que[y]];
}
void Solve()
{ll head=1,tail=2;que[1]=1,dp[1]=0;for(int i=2;i<=n;i++){while(head<tail-1&&f1(head+1,head)<f2(head,head+1)*a[i])head++;dp[i]=dp[que[head]]+b[que[head]]*a[i];while(head<tail-1&&tail>2&&(double)f1(tail-1,tail-2)/f2(tail-2,tail-1)>=(double)(dp[i]-dp[que[tail-1]])/(b[que[tail-1]]-b[i]))tail--;que[tail++]=i;}printf("%lld\n",dp[n]);
}
int main()
{scanf("%lld",&n);for(int i=1;i<=n;i++)scanf("%lld",&a[i]);for(int i=1;i<=n;i++)scanf("%lld",&b[i]);Solve();return 0;
}

【单调队列优化】CF319C——Kalila and Dimna in the Logging Industry相关推荐

  1. 算法笔记--单调队列优化dp

    单调队列:队列中元素单调递增或递减,可以用双端队列实现(deque),队列的前面和后面都可以入队出队. 单调队列优化dp: 问题引入: dp[i] = min( a[j] ) ,i-m < j ...

  2. 多重背包单调队列优化思路_多重背包之单调队列优化理论性总结

    多重背包之单调队列优化: 若用F[j]表示对容量为j的背包,处理完前i种物品后,背包内物品可达到的最大总价值,并记m = min(n, j / v).放入背包的第i种物品的数目可以是:0.1.2--, ...

  3. tyvj1305 最大子序和 【单调队列优化dp】

    描述 输入一个长度为n的整数序列,从中找出一段不超过M的连续子序列,使得整个序列的和最大. 例如 1,-3,5,1,-2,3 当m=4时,S=5+1-2+3=7 当m=2或m=3时,S=5+1=6 输 ...

  4. poj 2373(单调队列优化dp)

    在长为L(<=1000000)的草地(可看成线段)上装喷水头,喷射是以这个喷水头为中心,喷水头的喷洒半径是可调节的调节范围为[a,b].要求草地的每个点被且只被一个喷水头覆盖,并且有些连续区间必 ...

  5. poj 1821(单调队列优化dp)

    题意:有一道线性篱笆由N个连续的木板组成.有K个工人,你要叫他们给木板涂色.每个工人有3个参数:L 表示 这个工人可以涂的最大木板数目,S表示这个工人站在哪一块木板,P表示这个工人每涂一个木板可以得到 ...

  6. POJ - 3926 Parade(单调队列优化dp)

    题目链接:点击查看 题目大意:给出一个n*m的街道,其中有(n+1)*m条街道,每条街道都有一个值,现在我们需要从最下面的任意一点出发,到达最上面的任意一点结束,问如何规划路线能让沿途经过的街道的权值 ...

  7. 多重背包单调队列优化思路_动态规划入门——多重背包与单调优化

    本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是算法与数据结构的第14篇文章,也是动态规划专题的第三篇. 在之前的文章当中,我们介绍了多重背包的二进制拆分的解法.在大多数情况下,这种 ...

  8. 单调队列优化和决策单调性优化

    前言:dp蒟蒻拼命挽救一下dp a....,会围绕三个"形如"来写...但更重要的是本质理解啊qwq A.单调队列优化: 有时状态转移方程形如f[i][j]=min{f[i-1][ ...

  9. 单调队列优化多重背包

    就是按照 % 体积的余数来分组,每组单调队列优化. 直接上模板好了. 1 #include <bits/stdc++.h> 2 3 typedef long long LL; 4 cons ...

最新文章

  1. 掌握Angular2的服务(service)
  2. visual studio系列(vs)启动调试网站使用ip+端口局域网访问
  3. 图像sobel梯度详细计算过程_数字图像处理(第十章)
  4. 插件式架构设计实践:插件式系统架构设计简介
  5. 软件部署在不同linux上,如何在Linux中安装和部署keepalived
  6. 关于go语言的测试相关内容笔记
  7. Atitit jsr规范化分类 attilax总结
  8. 【Linux】04 软链接和硬链接
  9. Parser-Free Virtual Try-on via Distilling Appearance Flows代码解析
  10. SWAT模型中土壤水文分组的一些思考
  11. Java查看某个类的帮助文档
  12. 小米笔记安装双系统linux,小米笔记本电脑怎么安装双系统?-小米win7
  13. 加法器verilog
  14. mysql源码分析——THD数据结构
  15. TREC之使用terrier进行信息检索
  16. 转:程序员应该怎样去学习和掌握计算机英语呢?
  17. 从这些企业的数字化转型实践中,你能得到什么启发
  18. spm12预处理步骤及知识点总结
  19. Java项目:SSH高校科研管理系统平台
  20. python如何判断web访问来源是PC端还是手机端

热门文章

  1. 一个机械研究生在计算机与机械之间的徘徊与思考-(下)之填坑
  2. 快递查询工具,如何查看单号在每个时间段的具体信息
  3. 安利三个工具,教你如何把英语翻译成中文
  4. C++自带string类的常用方法
  5. 打开Xmind提示The contiolrator Userslwangappication DatalXMindlconfiquration-cathy win32-R3.79.2019120523
  6. 3Dmax使用者快速上手Maya心得之建模
  7. 未来10年计算机专业会不会淘汰,未来10年不会“被淘汰”的4个专业,发展潜力较大,就业前景可观...
  8. 在iPad上使用Office 365
  9. 《痞子衡嵌入式半月刊》 第 21 期
  10. Java集合判空/非空