[HNOI2008]玩具装箱(1D/1D动态规划)

[HNOI2008]玩具装箱

题目描述

P 教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京。他使用自己的压缩器进行压缩,其可以将任意物品变成一堆,再放到一种特殊的一维容器中。

P 教授有编号为 1 ⋯ n 1 \cdots n 1n n n n 件玩具,第 i i i 件玩具经过压缩后的一维长度为 C i C_i Ci

为了方便整理,P教授要求:

  • 在一个一维容器中的玩具编号是连续的。

  • 同时如果一个一维容器中有多个玩具,那么两件玩具之间要加入一个单位长度的填充物。形式地说,如果将第 i i i 件玩具到第 j j j 个玩具放到一个容器中,那么容器的长度将为 x = j − i + ∑ k = i j C k x=j-i+\sum\limits_{k=i}^{j}C_k x=ji+k=ijCk

制作容器的费用与容器的长度有关,根据教授研究,如果容器长度为 x x x,其制作费用为 ( x − L ) 2 (x-L)^2 (xL)2。其中 L L L 是一个常量。P 教授不关心容器的数目,他可以制作出任意长度的容器,甚至超过 L L L。但他希望所有容器的总费用最小。

输入格式

第一行有两个整数,用一个空格隔开,分别代表 n n n L L L

2 2 2 到 第 ( n + 1 ) (n + 1) (n+1) 行,每行一个整数,第 ( i + 1 ) (i + 1) (i+1) 行的整数代表第 i i i 件玩具的长度 C i C_i Ci

输出格式

输出一行一个整数,代表所有容器的总费用最小是多少。

样例 #1

样例输入 #1
5 4
3
4
2
1
4
样例输出 #1
1

提示

对于全部的测试点, 1 ≤ n ≤ 5 × 1 0 4 1 \leq n \leq 5 \times 10^4 1n5×104 1 ≤ L ≤ 1 0 7 1 \leq L \leq 10^7 1L107 1 ≤ C i ≤ 1 0 7 1 \leq C_i \leq 10^7 1Ci107

题解

这道题的许多题解都是用斜率优化DP做的,现在我给大家讲一下 1 D / 1 D 1D/1D 1D/1D动态规划中的决策单调性优化的方法来做这道题。

首先,我们可以很容易地求出这题的 1 D / 1 D 1D/1D 1D/1D的动态规划方程:

f ( i ) = min ⁡ j = 1 i − 1 f j + w j + 1 , i f(i)=\min\limits_{j=1}^{i-1}f_j+w_{j+1,i} f(i)=j=1mini1fj+wj+1,i,其中 w i , j = ( j − i + ∑ k = i j c k − L ) 2 w_{i,j}=(j-i+\sum\limits_{k=i}^jc_k-L)^2 wi,j=(ji+k=ijckL)2

k ( i ) k(i) k(i)表示状态 i i i取到最优值时的决策,则

∀ i ≤ j , k ( i ) ≤ k ( j ) \forall i\leq j,k(i)\leq k(j) ij,k(i)k(j)当且仅当:

∀ i ≤ j , w i , j + w i + 1 , j + 1 ≤ w i + 1 , j + w i , j + 1 \forall i\leq j,w_{i,j}+w_{i+1,j+1}\leq w_{i+1,j}+w_{i,j+1} ij,wi,j+wi+1,j+1wi+1,j+wi,j+1

以上是有关四边形不等式的知识,大家可以自行学习,这里不再赘述。

根据计算,DP式中的 w w w数组是满足上述条件的,所以 k ( i − 1 ) ≤ k ( i ) k(i-1)\leq k(i) k(i1)k(i)。于是,在枚举 i i i的时候,可以从 k ( i − 1 ) k(i-1) k(i1)开始枚举。但是,虽然减少了枚举次数,但在最坏情况下,时间复杂度还是 O ( n 2 ) O(n^2) O(n2)的。

我们可以换一个角度,每得出一个 f ( i ) f(i) f(i),考虑 f ( i ) f(i) f(i)能更新的状态有哪些。因为满足单调性,我们只需要找到第一个 f ( i ) f(i) f(i)能更新的状态,那么从这个状态到最后一个状态 f ( i ) f(i) f(i)都可以更新。

于是,我们可以用一个栈来维护数据。栈中的每个元素保存一个决策能更新到的起始位置和终止位置。当插入一个新位置时从栈中最后一个元素扫描,如果新决策能更新栈尾的决策的起始点,则将栈尾的元素删除出栈;如果不能更新,则在栈尾元素的起始位置和终止位置中二分查找第一个点 t t t,使该点能够被新决策更新。栈尾决策的终止点改为 t t t前一个点,新元素的起始点为 t t t,终止点为最后一个点。

总时间复杂度为 O ( n log ⁡ n ) O(n\log n) O(nlogn)

code

#include<bits/stdc++.h>
using namespace std;
int n,tp;
long long l,c[50005],sum[50005],f[50005];
struct node{
    int l,r,id;
}v[50005];
int find(int op){
    int l=1,r=tp,mid;
    while(l<=r){
        mid=(l+r)/2;
        if(op>v[mid].r) l=mid+1;
        else if(op<v[mid].l) r=mid-1;
        else if(op>=v[mid].l&&op<=v[mid].r) return v[mid].id;
    }
    return 0;
}
long long tw(long long a){
    return a*a;
}
long long w(int i,int j){
    return tw(j-i+sum[j]-sum[i-1]-l);
}
bool pd(int i,int j,int k){
    return f[i]+w(i+1,k)<f[j]+w(j+1,k);
}
void pt(int t){
    while(tp){
        if(v[tp].l>t&&pd(t,v[tp].id,v[tp].l)) --tp;
        else break;
    }
    int l=v[tp].l,r=v[tp].r,mid,ch=v[tp].r+1;
    while(l<=r){
        mid=(l+r)/2;
        if(pd(t,v[tp].id,mid)){
            ch=mid;r=mid-1;
        }
        else l=mid+1;
    }
    v[tp].r=ch-1;
    if(ch<=n) v[++tp]=(node){ch,n,t};
}
int main()
{
    scanf("%d%lld",&n,&l);
    for(int i=1;i<=n;i++){
        scanf("%lld",&c[i]);
        sum[i]=sum[i-1]+c[i];
    }
    v[++tp]=(node){1,n,0};
    for(int i=1;i<=n;i++){
        int j=find(i);
        f[i]=f[j]+w(j+1,i);
        pt(i);
    }
    printf("%lld",f[n]);
}
  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
动态规划知识点及一些常见问题分析。动态规划基本原理.........................................................................................................................1 机器分配(HNOI’95)................................................................................................................. 3 最长不下降序列(HNOI’97)..................................................................................................... 4 凸多边形三角划分(HNOI’97)................................................................................................. 6 系统可靠性(HNOI’98)............................................................................................................. 8 快餐问题(HNOI’99)................................................................................................................. 9 求函数最大值(CTSC'95)............................................................................................................. 14 石子合并(NOI’95).................................................................................................................. 15 游览街区(NOI’97).................................................................................................................. 17 积木游戏(NOI’97).................................................................................................................. 20 免费馅饼(NOI’98).................................................................................................................. 24 棋盘分割(NOI’99).................................................................................................................. 27 钉子和小球(NOI’99).............................................................................................................. 30 等。。。
根据引用\[1\]和引用\[2\]的描述,题目中的影魔拥有n个灵魂,每个灵魂有一个战斗力ki。对于任意一对灵魂对i,j (i<j),如果不存在ks (i<s<j)大于ki或者kj,则会为影魔提供p1的攻击力。另一种情况是,如果存在一个位置k,满足ki<c<kj或者kj<c<ki,则会为影魔提供p2的攻击力。其他情况下的灵魂对不会为影魔提供攻击力。 根据引用\[3\]的描述,我们可以从左到右进行枚举。对于情况1,当扫到r\[i\]时,更新l\[i\]的贡献。对于情况2.1,当扫到l\[i\]时,更新区间\[i+1,r\[i\]-1\]的贡献。对于情况2.2,当扫到r\[i\]时,更新区间\[l\[i\]+1,i-1\]的贡献。 因此,对于给定的区间\[l,r\],我们可以根据上述方法计算出区间内所有下标二元组i,j (l<=i<j<=r)的贡献之和。 #### 引用[.reference_title] - *1* *3* [P3722 [AH2017/HNOI2017]影魔(树状数组)](https://blog.csdn.net/li_wen_zhuo/article/details/115446022)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [洛谷3722 AH2017/HNOI2017 影魔 线段树 单调栈](https://blog.csdn.net/forever_shi/article/details/119649910)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值