大致题意
有 个点,每个点有一个属性 , 单调递增,从 点移动到大于 的 点,需要付出 的代价,其中 题中已给出,求点 移动到点 的最小代价。
思路/解析
设 表示从点 移动到点 的最小代价,容易列出状态转移方程为 。
直接转移的时间复杂度是 ,无法通过本题,于是运用斜率优化,公式就变为了
将状态 视为平面上的点 ,问题就变成了求最小的斜率固定的直线的截距,因为 单调递增,所以点的坐标也单调递增,斜率也单调递增。使用单调队列维护下凸壳,即可通过本题。
代码
cpp
#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';
}