这是一道单调队列的板题
题目链接(Luogu)
Codeforces
题意
伐木工人用电锯伐木,一共需要砍
棵树,每棵树的高度为
,每次砍伐只能砍
单位高度,之后需要对电锯进行充电,费用为当前砍掉的树中最大
的
值
思路
因为有
,所以当砍掉第
棵树时就不需要花钱了
从这个角度入手,可以考虑定义
为砍第
棵树的花费
那么就可以轻松的得到一个
的状态转移方程式:
但是一看数据范围
,朴素的
明显行不通
我们再来看这个转移式,因为每次转移只跟
有关,我们考虑使用斜率优化
假设有:
且
比
优
那么有:
移项过后就是:
这个就是我们的斜率式了
维护一个队列就可以使复杂度降低到
代码
具体实现请看代码
const int N = 1e5 + 5;
ll dp[N];
int n, a[N], b[N], q[N], head, tail;
double getk(int x, int y)
{
return 1.0 * (dp[y] - dp[x]) / (b[x] - b[y]);
}
int main()
{
ios :: sync_with_stdio(0);
cin >> n;
for (int i = 1; i <= n; i++)
cin >> a[i];
for (int i = 1; i <= n; i++)
cin >> b[i];
q[++tail] = 1;
head = 1;
for (int i = 2; i <= n; i++)
{
while (head < tail && getk(q[head], q[head + 1]) < a[i])
head++;
dp[i] = dp[q[head]] + 1ll * a[i] * b[q[head]];
while (head < tail && getk(q[tail], i) <= getk(q[tail - 1], q[tail]))
tail--;
q[++tail] = i;
}
cout << dp[n];
return 0;
}