AT_dp_z Frog3(斜率优化 DP)

Atcoder 题目传送门

洛谷题目传送门

洛谷有题目翻译

解题思路

设 f(i) 表示青蛙跳到第 i 个石头的最小花费。

根据题意,易得转移方程:

f(i)=\min(f(j)+(h_i-h_j)^2+c)

(其中 j<i

这样的时间复杂度是 O(n^2) 的,会超时。

所以我们考虑斜率优化。

斜率优化

将上面的转移方程展开,得:

f(i)=f(j)+h_i^2+h_j^2-2h_ih_j +c

将 i 看作常数,将 j 看作未知数,移项得:

-f(j)-h_j^2=-f(i)+h_i^2-2h_ih_j+c

两边同时 \times -1,得:

f(j)+h_j^2=2h_ih_j+f(i)-h_i^2-c

对比 y=kx+b,你就会发现:

y=f(j)+h_j^2

k=2h_i

x=h_j

b=f(i)-h_i^2-c

观察 k 和 x,由于 h_i 是递增的,所以无需二分或 CDQ 分治。

直接斜率优化即可。

代码

注意:由于青蛙是从第一个石头开始跳的,所以我们不用将 0 号点加入凸包中。

#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,c;
int h[200001];
int f[200001];
int q[200001];

int dx(int i,int j)
{
	int x1=h[i];
	int x2=h[j];
	return x1-x2;
}
int dy(int i,int j)
{
	int y1=f[i]+(h[i]*h[i]);
	int y2=f[j]+(h[j]*h[j]);
	return y1-y2;
}
main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	
	cin>>n>>c;
	for(int i=1;i<=n;i++)
	{
		cin>>h[i];
	}
	
	int head=1,tail=0;
	for(int i=2;i<=n;i++)
	{
		while(head<tail&&dy(q[tail],q[tail-1])*dx(i-1,q[tail])>=dx(q[tail],q[tail-1])*dy(i-1,q[tail]))
			tail--;
		q[++tail]=i-1;
		while(head<tail&&dy(q[head+1],q[head])<=2*h[i]*dx(q[head+1],q[head]))
			head++;
		int j=q[head];
		f[i]=f[j]+(h[i]-h[j])*(h[i]-h[j])+c;
	}
	cout<<f[n];
	return 0;
 } 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值