243 字
1 分钟

AT_dp_z Frog 3 题解

2023-08-06
浏览量 加载中...

大致题意#

nn 个点,每个点有一个属性 hih_ihih_i 单调递增,从 ii 点移动到大于 iijj 点,需要付出 (hihj)2+c(h_i-h_j)^2+c 的代价,其中 cc 题中已给出,求点 11 移动到点 nn 的最小代价。

思路/解析#

fif_i 表示从点 11 移动到点 ii 的最小代价,容易列出状态转移方程为 fi=minj<i(fj+(aiaj)2+c)f_i=\min_{j<i}(f_j+(a_i-a_j)^2+c)

直接转移的时间复杂度是 O(n2)O(n^2),无法通过本题,于是运用斜率优化,公式就变为了

fi=fj+ai22aiaj+aj2+c(fiai2)=(fj+aj2+c)(2ai)(aj)\begin{aligned}f_i&=f_j+a_i^2-2a_ia_j+a_j^2+c\\(f_i-a_i^2)&=(f_j+a_j^2+c)-(2a_i)(a_j)\end{aligned}

将状态 ii 视为平面上的点 (ai,fi+ai2+c)(a_i,f_i+a_i^2+c),问题就变成了求最小的斜率固定的直线的截距,因为 aia_i 单调递增,所以点的坐标也单调递增,斜率也单调递增。使用单调队列维护下凸壳,即可通过本题。

代码#

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N=2e5+10;
ll n,c,i,l,r,h[N],q[N],dp[N];
double Y(ll j){return dp[j]+h[j]*h[j];}
double X(ll i){return h[i]<<1;}
double K(ll i,ll j){return (Y(i)-Y(j))/((X(i)-X(j)));}
int main(){
cin>>n>>c;
for(i=1;i<=n;i++)cin>>h[i];
l=r=q[1]=1;
for(i=2;i<=n;i++){
while(l<r&&h[i]>=K(q[l],q[l+1]))l++;
dp[i]=dp[q[l]]+c+(h[i]-h[q[l]])*(h[i]-h[q[l]]);
while(l<r&&K(q[r-1],q[r])>=K(q[r],i))r--;
q[++r]=i;
}
cout<<dp[n]<<'\n';
}

支持与分享

如果这篇文章对你有帮助,欢迎分享给更多人或赞助支持!

赞助
AT_dp_z Frog 3 题解
https://blog.walterfang.site/posts/solution-at_dp_z/
作者
Walter_Fang
发布于
2023-08-06
许可协议
CC BY-NC-SA 4.0
最后更新于 2023-08-06,距今已过 885 天

部分内容可能已过时

评论区

目录