Frog 3
Frog 3
题目大意
一只青蛙,\(n\) 个柱子,每个柱子高 \(h_i\) 青蛙从一个柱子跳到另一个柱子需要花费 \((h_i-h_j)^2+C\) 点能量,\(C\) 为给定常数。问最小花费。
题解
普通的 \(dp\) 式子: \(dp_i=\min\limits_{0\le j<i} dp_j+(h_i-h_j)^2+C\)
这看着复杂度就是 \(O(n^2)\) 的,过不了。
看上面的式子,我们把 \(min\) 去掉后,就变成了 \(dp_i=dp_j+(h_i-h_j)^2+C\)
拆个括号在移一下项就变成了 \(dp_i-C-h_i^2=dp_j+h_j^2-2h_ih_j\) 。
对这个式子看着有 \(i\) 和 \(j\) 同时出现的项 ,就很能斜率优化的样子。
把 \(j\) 的项单独拎出来设 \(f_j=dp_j+h_j^2\) ,就变成了 \(f_j-2h_ih_j\),我们再设 \(k=-2h_i\) 这个式子就变成了 \(kh_j+f_j\) ,看着就很想 \(y=kx+b\) 。
若此时有两个变量 \(j_1,j_2,j_1<j_2\) 且 \(j_2\) 不比 \(j_1\) 优,需满足:
\(f(j_1)+h_{j_1}\times k\le f(j_2)+h_{j_2}\times k\)
\(2h_i\le \frac{f(j_1)-f(j_2)}{h_{j_1}-h_{j_2}}\)
完成。
代码
#include <bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define rep(i, a, b) for (int i = a; i <= b; i++)
#define per(i, a, b) for (int i = a; i >= b; i--)
#define mkp make_pair
#define pll pair<ll, ll>
char *SSSS, *TTTT;
char pori[1 << 22];
#define gc() (SSSS == TTTT && (TTTT = (SSSS = pori) + fread(pori, 1, 1 << 22, stdin)), SSSS == TTTT ? EOF : *SSSS++)
using namespace std;
inline ll read()
{
ll x = 0, f = 1;
char ch = gc();
while (ch < '0' || ch > '9')
{
if (ch == '-')
{
f = -1;
}
ch = gc();
}
while (ch >= '0' && ch <= '9')
{
x = (x << 1) + (x << 3) + ch - '0';
ch = gc();
}
return x * f;
}
const ll N = 2e5 + 5;
ll h[N], f[N];
inline double y(ll x)
{
return f[x] + h[x] * h[x];
}
inline double x(ll x)
{
return h[x];
}
inline double slope(ll a, ll b)
{
return (y(a) - y(b)) / (x(a) - x(b));
}
ll q[N];
ll hd, tl;
int main()
{
ll n = read(), c = read();
rep(i, 1, n)
{
h[i] = read();
}
hd = 1, tl = 0;
q[++tl] = 1;
rep(i, 2, n)
{
while (hd < tl && slope(q[hd], q[hd + 1]) <= 2 * h[i])
{
hd++;
}
ll j = q[hd];
f[i] = f[j] + (h[i] - h[j]) * (h[i] - h[j]) + c;
while (hd < tl && slope(q[tl - 1], q[tl]) >= slope(q[tl], i))
{
tl--;
}
q[++tl] = i;
}
printf("%lld\n", f[n]);
return 0;
}

浙公网安备 33010602011771号