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;
}

posted @ 2025-06-15 22:46  点燃genshin  阅读(19)  评论(0)    收藏  举报