[HNOI2008]玩具装箱TOY

题意

Here

思考

写的第一道斜率优化…感觉这个板题还蛮简单的

首先按普通思路,我们令 \(dp[i]\),为前 \(i\) 个物品的最小价值,那么可以很容易列出方程:

\[dp[i] = min\{ dp[j]+(sum[i]-sum[j]+i-j-1-L)^2 \} \]

这是一个 \(O(n^2)\)\(dp\),我们考虑如何优化它:

\(s[x] = sum[x] + x,\ L=L+1\),则

\[dp[i] = dp[j]+(sum[i]-sum[j]+i-j-1-L)^2 \\ = dp[j] + (s[i] - s[j] - L) ^ 2 \\ = dp[j] + s[i]^2 + (s[j]+L)^2 - 2*s[i]*(s[j]+L)\]

等式整理为:

\[dp[i] + 2 * s[i] * (s[j] + L) = dp[j] + s[i]^2 + (s[j] + L) ^ 2 \]

在这个式子里面,我们把 \(dp[j] + s[i]^2 + (s[j] + L)\) 看作因变量, \(s[j]+L\)看作自变量,\(dp[i]\) 看作 \(y\) 轴截距,\(2*s[i]\)(已知量)看作直线斜率,那么我们就是要找到一个决策点 \(j\) 使得截距最小,根据 \(k=2*s[i]\) 我们可以发现这个斜率是单调递增的,那么我们维护的是一个下凸包,不多赘述。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double D;
const int N = 50050;
ll f[N], s[N], sum[N], n, L;
ll q[N], h, t;
D X(ll i){ return (D)s[i] + (D)L; }
D Y(ll i){ return (D)f[i] + (D)X(i) * (D)X(i); }
D slope(ll i, ll j){ return ( Y(i) - Y(j) ) / ( X(i) - X(j) ); }
int main(){
    cin >> n >> L; L ++;
    for(ll i=1; i<=n; i++) cin >> sum[i], sum[i] += sum[i-1], s[i] = sum[i] + i;
    h = 1, t = 1;
    for(ll i=1; i<=n; i++){
        while(h < t && slope(q[h], q[h+1]) <= 2 * s[i]) h ++;
        f[i] = f[q[h]] + (s[i] - s[q[h]] - L) * (s[i] - s[q[h]] - L);
        while(h < t && slope(q[t], q[t-1]) >= slope(q[t], i)) t --;
        q[++t] = i;
    }
    cout << f[n];
    return 0;
}

总结

斜率优化中某些无关量可以在计算斜率的时候消去,所以不用管。

注意当前不变量和变量之间的关系。

注意变量类型。

posted @   alecli  阅读(115)  评论(0编辑  收藏  举报
努力加载评论中...
点击右上角即可分享
微信分享提示