Codeforces 320E Kalila and Dimna in the Logging Industry【思维+贪心+斜率优化Dp】好题!
2017-10-09 15:44
555 查看
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 < 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 %I64dspecifier.
Examples
input
output
input
output
题目大意:
给出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
);
}
}
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 < 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 %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
);
}
}
相关文章推荐
- CodeForces 631E Product Sum(斜率优化DP+二分|三分) ★
- CodeForces 311B/CSU 1963 Cats Transport/Feed The Rabbit(斜率优化dp)
- CodeForces - 660F:Bear and Bowling 4(DP+斜率优化)
- Codeforces 643C Levels and Regions(斜率优化dp)
- codeforces-486【C-贪心-思维】【D-树状DP】
- Codeforces 373E Watching Fireworks is Fun【思维+单调队列优化Dp+滚动数组】
- bzoj 1492: [NOI2007]货币兑换Cash【贪心+斜率优化dp+cdq】
- DP训练 Codeforces 673E Levels and Regions [斜率优化dp][期望]
- CodeForces 631E Product Sum(斜率优化DP+二分|三分)
- CodeForces - 459E Pashmak and Graph[贪心优化dp]
- CodeForces - 311B:Cats Transport (DP+斜率优化)
- poj 3709 K-Anonymous Sequence 斜率优化dp
- 斜率优化DP
- dp斜率优化 Hdu 3480 Division 题解
- hdu 3507 Print Article(DP+斜率优化)
- 【BZOJ1911】【codevs1318】特别行动队,斜率优化DP
- hdu3507 Print Article DP+斜率优化
- 【HDU 3507】Print Article(斜率优化DP)
- CodeForces - 711C Coloring Trees(DP)(思维)
- 【斜率优化dp】bzoj 1597 土地购买