Codeforces 320E Kalila and Dimna in the Logging Industry【思维+贪心+斜率优化Dp】好题!

本文介绍了一个关于砍树的问题,通过斜率优化的动态规划方法解决。需要考虑如何最小化砍倒所有树木的成本,同时注意到树木高度和充电成本的特性。

E. Kalila and Dimna in the Logging Industry
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

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 < jai < 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 = 1bn = 0a1 < 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 cincout streams or the %I64dspecifier.

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个树,从左到右编号为1~N,我们有一个电锯,电锯有电的时候可以使得一棵树的高度减少1,我们充电的花费是已经砍倒的最大编号(i)的那棵树的B【i】的值,我们的电锯一开始是充满电的,问将所有树都砍倒的最小花费。

保证a【i】是递增的而且a【1】=1,b【i】是递减的,而且b【n】=0;


思路:


①根据数据的特性,我们不难想到去Dp做这个题,设定Dp【i】表示砍倒了位子i的树的最小花费,那么不难写出其状态转移方程:

Dp【i】=min(Dp【i】,Dp【j】+Sum【j+1,i】*a【i】+a【i】*b【j】);

但是考虑到b【i】是递减的同时,b【n】又是0,所以我们的终极目标就是将编号为n的那棵树砍倒,那么之前没有砍倒的树就都能无花费去砍倒了。那么贪心优化转移:

Dp【i】=min(Dp【i】,Dp【j】+a【i】*b【j】);


②观察到Dp【i】和b【j】的值有关,那么直接用优先队列或者是线段树优化转移是不可能的,这里要考虑决策单调性。

所以这类题一定是斜率优化去做。


如果存在位子j和k,j>k&&对于当前要转移的位子i,位子j的转移更优的话,那么就存在:

Dp【j】+a【i】*b【j】<=Dp【k】+a【i】*b【k】;

化简不等式有:

Dp【j】-Dp【k】<=a【i】*(b【k】-b【j】);

不难想到,再将右侧括号内部分除到左边,就满足了斜率,那么如果存在这样的情况的话,我们肯定以后所有位子都是去选择位子j而非位子k。


那么过程维护一个优先队列去转移就行了。注意乘爆LL。


Ac代码:

#include<stdio.h>
#include<string.h>
using namespace std;
#define ll __int64
ll n;
ll a[150000];
ll b[150000];
ll sum[150000];
ll dp[150000];
ll que[150000];
ll A(ll j,ll k)
{
    return dp[j]-dp[k];
}
ll B(ll j,ll k)
{
    return b[k]-b[j];
}
ll Cal(ll i,ll j)
{
    return dp[j]+a[i]*b[j];
}
int main()
{
    ll n;
    while(~scanf("%I64d",&n))
    {
        sum[0]=0;
        memset(dp,0,sizeof(dp));
        for(ll i=1;i<=n;i++)scanf("%I64d",&a[i]);
        for(ll i=1;i<=n;i++)scanf("%I64d",&b[i]);
        for(ll i=1;i<=n;i++)sum[i]=sum[i-1]+a[i];
        ll head,tot;
        head=tot=0;
        que[tot++]=1;
        for(ll i=2;i<=n;i++)
        {
            while(head+1<tot&&A(que[head+1],que[head])*1.0/(B(que[head+1],que[head])*1.0)<=a[i]*1.0)head++;
            dp[i]=Cal(i,que[head]);
            while(head+1<tot&&A(i,que[tot-1])*1.0/B(i,que[tot-1])*1.0<=A(que[tot-1],que[tot-2])*1.0/B(que[tot-1],que[tot-2])*1.0)tot--;
            que[tot++]=i;
        }
        printf("%I64d\n",dp[n]);
    }
}














### 关于斜率优化动态规划的目列表 在Codeforces平台上存在多个涉及斜率优化动态规划(DP)的挑战性问。这类算法通常用于解决具有特定结构化状态转移方程的问,其中决策变量之间的关系可以通过几何特性——特别是直线间的相对位置变化来有效处理。 #### 例子一:Cats Transport 在此中,给定了`p`个人运输猫的任务安排模型[^3]。每次操作都基于先前的状态进行更新,即当前层的结果依赖于上一层的数据计算而来。具体表达式如下所示: ```cpp dp[k][i] = dp[k-1][j] + A[i]*(i-j) - (S[i] - S[j]); ``` 此公式展示了如何利用历史最优解构建新的解决方案,并引入了线性函数的概念以便后续应用斜率优化技巧。 #### 例子二:The Fair Nut and Rectangles 该问描述了一个更复杂的场景,在这里不仅涉及到简单的数值运算,还需要考虑二维平面上矩形的选择策略以最大化收益差额[^4]。其核心在于巧妙地定义状态空间以及相应的转换逻辑,从而允许采用高效的斜率优化方法加速求解过程。 为了帮助更好地理解和练习此类技术,下面列举了一些适合初学者和中级选手尝试的经典习链接(请注意实际编号可能会有所变动): - **CF317E**. [Ostap and Tree](https://codeforces.com/problemset/problem/317/E): 虽然名字里提到树,但这道实际上是关于路径覆盖的一个变种版本。 - **CF629F**. [Polygons on the Grid](https://codeforces.com/problemset/problem/629/F): 这是一个典型的多边形放置类问,非常适合用来熟悉斜率优化的思想。 - **CF1083E**. [The Fair Nut and Rectangles](https://codeforces.com/problemset/problem/1083/E): 如前所述,这是一个很好的综合案例研究对象。 - **CF580E**. [Kefa and Watch](https://codeforces.com/problemset/problem/580/E): 尽管表面上看起来像是贪心或者记忆化搜索可以搞定的事情,但实际上背后隐藏着精妙的斜率优化机制等待挖掘。 这些资源能够提供丰富的实践机会,有助于深入掌握斜率优化DP这一强大工具的应用范围及其局限所在。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值