BZOJ1010:[HNOI2008] 玩具装箱toy(斜率优化)

  • 题意

    求将一个长为\(n\)的序列(每个数为\(c_i\))分为很多段,每段(\(i\)~\(j\))的花费是\((j-i+\sum_{k=i}^{j}c_k-L)^2\),求最小的花费。(\(n<=50000\))

  • 题解

    容易看出\(dp\)式子如下

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

    这个式子为\(O(n^2)\)的复杂度,显然过不去,我们进行一下斜率优化就能优化一维枚举决策点的复杂度,变成\(O(n)\)了。

    接下来就需要拆式子,右边有六项,十分的难拆,但我们可以将与\(j\)有关和与\(j\)无关的分开,所以我们可以将这个式子进行一个简单的分割。

    即让\(a[i]\)为\(sum[i]+i-1-L\),\(b[j]\)为\(sum[j]+j\)。

    原式就化为了\(dp[i]=min\{dp[j]+(a[i]-b[j])^2\} \quad (j < i)\)

    \(dp[i]=min\{dp[j]+a[i]^2-a[i]*b[j]+b[j]^2\}\)

    当\(j\)比\(k\)更优的时候满足\((k<j)\)

    \(dp[j]-2*a[i]*b[j]+b[j]^2<dp[k]-2*a[i]*b[k]+b[k]^2\)

    \((dp[j]+b[j]^2)-(dp[k]+b[k]^2)<2*a[i]*(b[j]-b[k])\)

    \(\frac{(dp[j]+b[j]^2)-(dp[k]+b[k]^2)}{(b[j]-b[k])} < 2*a[i]\)

    然后\(a[i]\)显然满足单调递增。可以用单调队列去维护。

    \(q[Head+1]\)比\(q[Head]\)要优,弹出队首。

    然后弹出队尾的时有些麻烦,但结论还是很简单的,如果\(k(q[Tail-1],q[Tail])\)斜率大于\(k(q[Tail],i)\)就可以弹出队尾。(这个可以简单证明一下)

    最后就直接可以每次将队首作为决策转移点去转移了。

  • 代码
#include <bits/stdc++.h>
#define For(i, l, r) for(register int i = (l), _end_ = (int)(r); i <= _end_; ++i)
#define Fordown(i, r, l) for(register int i = (r), _end_ = (int)(l); i >= _end_; --i)
#define Set(a, v) memset(a, v, sizeof(a))
using namespace std;

inline bool chkmin(int &a, int b) {return b < a ? a = b, 1 : 0;}
inline bool chkmax(int &a, int b) {return b > a ? a = b, 1 : 0;}

inline int read() {
    int x = 0, fh = 1; char ch = getchar();
    for (; !isdigit(ch); ch = getchar() ) if (ch == ‘-‘) fh = -1;
    for (; isdigit(ch); ch = getchar() ) x = (x<<1) + (x<<3) + (ch ^ ‘0‘);
    return x * fh;
}

void File() {
#ifdef zjp_shadow
    freopen ("P1010.in", "r", stdin);
    freopen ("P1010.out", "w", stdout);
#endif
}

typedef long long ll;
const int N = 50100;
int n;
ll sum[N], dp[N], L;
ll a[N], b[N];

#define pow2(x) ((x) * (x))
inline ll Dp(int i, int j) {
    return dp[j] + pow2(a[i] - b[j]);
}

inline ll Up(int j, int k) {
    return (dp[j] + pow2(b[j]) ) - (dp[k] + pow2(b[k]) );
}

inline ll Down(int j, int k) {
    return b[j] - b[k];
}

int q[N];
int Head, Tail = 1;

int main () {
    File() ;
    n = read();
    L = read();
    a[0] = - 1 - L;
    For (i, 1, n) {
        sum[i] = sum[i - 1] + read();
        b[i] = sum[i] + i;
        a[i] = b[i] - 1 - L;
    }

    Set(dp, 0x3f); dp[0] = 0;
    For (i, 1, n) {
        while (Head + 1 < Tail && Up(q[Head + 1], q[Head]) <= 2 * a[i] * Down(q[Head + 1], q[Head]) ) ++ Head;
        dp[i] = Dp(i, q[Head]);

        while (Head + 1 < Tail && Up(i, q[Tail - 1]) * Down(q[Tail - 1], q[Tail - 2]) <= Up(q[Tail - 1], q[Tail - 2]) * Down(i, q[Tail - 1]) )  -- Tail;
        q[Tail ++] = i;
    }

    printf ("%lld\n", dp[n]);
    return 0;
}

原文地址:https://www.cnblogs.com/zjp-shadow/p/8228281.html

时间: 2024-12-21 03:17:49

BZOJ1010:[HNOI2008] 玩具装箱toy(斜率优化)的相关文章

[BZOJ1010] [HNOI2008] 玩具装箱toy (斜率优化)

Description P教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京.他使用自己的压缩器进行压缩,其可以将任意物品变成一堆,再放到一种特殊的一维容器中.P教授有编号为1...N的N件玩具,第i件玩具经过压缩后变成一维长度为Ci.为了方便整理,P教授要求在一个一维容器中的玩具编号是连续的.同时如果一个一维容器中有多个玩具,那么两件玩具之间要加入一个单位长度的填充物,形式地说如果将第i件玩具到第j个玩具放到一个容器中,那么容器的长度将为 x=j-i+Sigma(Ck) i<

BZOJ 1010: [HNOI2008]玩具装箱toy 斜率优化DP

1010: [HNOI2008]玩具装箱toy Description P教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京.他使用自己的压缩器进行压缩,其可以将任意物品变成一堆,再放到一种特殊的一维容器中.P教授有编号为1...N的N件玩具,第i件玩具经过压缩后变成一维长度为Ci.为了方便整理,P教授要求在一个一维容器中的玩具编号是连续的.同时如果一个一维容器中有多个玩具,那么两件玩具之间要加入一个单位长度的填充物,形式地说如果将第i件玩具到第j个玩具放到一个容器中,那么容器

HNOI2008玩具装箱 (斜率优化)

总算A了,心情好激动-- 如果会了一类斜率优化,基本上这类题就成了套模版了-- 只是k函数不同 1 var n,l,x,tail,head,m:int64; 2 i,j:longint; 3 dp,q,s:array[0..100000] of int64; 4 function k(x,y:longint):double; 5 begin 6 k:=1.0*((dp[x]+s[x]*s[x]-dp[y]-s[y]*s[y])/(s[x]-s[y])); 7 end; 8 procedure m

【斜率优化】BZOJ1010 [HNOI2008]玩具装箱toy

[题目大意] P教授有编号为1...N的N件玩具,第i件玩具长度为Ci.为了方便整理,P教授要求在一个一维容器中的玩具编号是连续的.如果将第i件玩具到第j个玩具放到一 个容器中,那么容器的长度将为 x=j-i+Sigma(Ck) i<=K<=j 制作容器的费用与容器的长度有关, 如果容器长度为x,其制作费用为(X-L)^2.其中L是一个常量.求最小费用. [思路] 懒得说了,把WC宋新波老师的课件搬运一下. 宋新波老师讲的很好,WC的时候第一次听斜率优化听他讲完秒懂了,时隔几个月再来消化一下.

bzoj1010: [HNOI2008]玩具装箱toy(斜率优化DP)

codevs也有这题,伪·双倍经验233 首先朴素DP方程很容易看出:f[i]=min(f[j]+(i-j-1+sum[i]-sum[j]-L)^2); 于是设g[i]=i+sum[i] g[j]=j+sum[j] c=1+L 则f[i]=min(f[j]+(g[i]-g[j]-c)^2) 证明决策单调性,假设 j 比 k 优 f[j]+(g[i]-g[j]-c)^2<f[k]+(g[i]-g[k]-c)^2 证明f[j]+(g[x]-g[j]-c)^2<f[k]+(g[x]-g[k]-c)^

BZOJ1010: [HNOI2008]玩具装箱toy

[传送门:BZOJ1010] 简要题意: 给出n条连续线段,每条线段都有长度为x[i],我们可以把连续若干条线段连在一起,变成一个组合,两条线段如果相连,就要在两条线段中间添加一个长度为1的格子(如果没有相连就不用添加),假如我们现在选择把第i条到第j条线段之间的所有线段变成一组合的话,这个组合的总长度就为:x[i]+x[i+1]+x[i+2]+x[i+3]+...+x[j]+j-i,现在给出一个常数L,假设当前选择的组合的长度为s,那么这个组合就为我们产生了(s-L)^2的费用,求出把n条线段

bzoj 1010 玩具装箱toy -斜率优化

P教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京.他使用自己的压缩器进行压缩,其可以将任意物品变成一堆,再放到一种特殊的一维容器中.P教授有编号为1...N的N件玩具,第i件玩具经过压缩后变成一维长度为Ci.为了方便整理,P教授要求在一个一维容器中的玩具编号是连续的.同时如果一个一维容器中有多个玩具,那么两件玩具之间要加入一个单位长度的填充物,形式地说如果将第i件玩具到第j个玩具放到一个容器中,那么容器的长度将为 x=j-i+Sigma(Ck) i<=K<=j 制作容器的

P3195 [HNOI2008]玩具装箱TOY DP+优化

题目描述 P教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京.他使用自己的压缩器进行压缩,其可以将任意物品变成一堆,再放到一种特殊的一维容器中.P教授有编号为1...N的N件玩具,第i件玩具经过压缩后变成一维长度为Ci.为了方便整理,P教授要求在一个一维容器中的玩具编号是连续的.同时如果一个一维容器中有多个玩具,那么两件玩具之间要加入一个单位长度的填充物,形式地说如果将第i件玩具到第j个玩具放到一个容器中,那么容器的长度将为 x=j-i+Sigma(Ck) i<=K<=j

BZOJ 1010: [HNOI2008]玩具装箱toy [DP 斜率优化]

1010: [HNOI2008]玩具装箱toy Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 9812  Solved: 3978[Submit][Status][Discuss] Description P教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京.他使用自己的压缩器进行压缩,其可以将任意物品变成一堆,再放到一种特殊的一维容器中.P教授有编号为1...N的N件玩具,第i件玩具经过压缩后变成一维长度为Ci.为了方便整理,P