[NOI 2014复习]斜率优化(BZOJ 1096、BZOJ 1010)

2023-10-28

1.BZOJ 1096 仓库建设

题目链接

http://www.lydsy.com/JudgeOnline/problem.php?id=1096

思路

f[i]=[1,i] 区间,在第i个工厂建立仓库,所需最少总花费。DP方程显然

f[i]=min1j<i{f[j]+w[j,i]}+C[i]

其中
w[j,i]=P[j+1](X[i]X[j+1])+P[j+2](X[i]X[j+2])+...+P[i](X[i]X[i])

w[j,i]=X[i]t=j+1iP[t]t=j+1iP[t]X[t]

sumP[i]=it=1P[t],sum[i]=it=1P[t]X[t]

设对于 f[i] 而言, x>y f[x] f[y] 更优,则

f[x]+w[x,i]<f[y]+w[y,i]

f[x]X[i]sumP[x]+sum[x]<f[y]X[i]sumP[y]+sum[y]

(f[x]+sum[x])(f[y]+sum[y])<X[i](sumP[x]sumP[y])

(sumP[x]sumP[y]) 除到左边去( 在做斜率优化时一定要注意除数的正负性,否则推出的式子可能会错!)
(f[x]+sum[x])(f[y]+sum[y])sumP[x]sumP[y]<X[i]

在单调队列里, (f[x]+sum[x])(f[y]+sum[y])sumP[x]sumP[y] 可以看作是队列中相邻的 x 点和y点连线的斜率,时刻维护单调队列中的元素的连线斜率( (f[x]+sum[x])(f[y]+sum[y])sumP[x]sumP[y] )单调递增(下凸壳)即可。

代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>

#define MAXN 2100000

using namespace std;

typedef long long int LL;

int n;
LL f[MAXN];
LL P[MAXN],C[MAXN],X[MAXN];
LL sum[MAXN],sumP[MAXN];
int q[MAXN];

inline LL W(int j,int i)
{
    return X[i]*(sumP[i]-sumP[j])-(sum[i]-sum[j]);
}

inline LL fracup(int x,int y)
{
    return (f[x]+sum[x])-(f[y]+sum[y]);
}

inline LL fracdn(int x,int y) //x>y
{
    return sumP[x]-sumP[y];
}

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%lld%lld%lld",&X[i],&P[i],&C[i]);
    for(int i=1;i<=n;i++)
        sum[i]=sum[i-1]+P[i]*X[i],sumP[i]=sumP[i-1]+P[i];
    int h=1,t=0;
    q[++t]=0;
    for(int i=1;i<=n;i++)
    {
        while(h<t&&fracup(q[h+1],q[h])<X[i]*fracdn(q[h+1],q[h])) h++;
        f[i]=f[q[h]]+W(q[h],i)+C[i];
        while(h<t&&fracup(q[t],q[t-1])*fracdn(i,q[t])>=fracup(i,q[t])*fracdn(q[t],q[t-1])) t--;
        q[++t]=i;
    }
    printf("%lld\n",f[n]);
    return 0;
}

2.BZOJ 1010 玩具装箱toy

题目链接

http://www.lydsy.com/JudgeOnline/problem.php?id=1010

思路

f[i]=[1,i] 部分装箱,且玩具i是玩具 [1,i] 装箱后,最右边那个箱子的右端点,装箱的最少费用。
容易得到DP方程:

f[i]=min1j<i{f[j]+(ij1+sum[i]sum[j]L)2}

为了方便叙述,以下约定 L=L1,sum[i]=sum[i]+i
DP方程就变成了:
f[i]=min1j<i{f[j]+(sum[i]sum[j]L)2}

x>y ,且对于 f[i] 而言, f[x] f[y] 更优,则
f[x]+(sum[i]sum[x]L)2<f[y]+(sum[i]sum[y]L)2

(f[x]+sum[x]22sum[x](sum[i]L))(f[y]+sum[y]22sum[y](sum[i]L))<0

f[x]+sum[x]2f[y]sum[y]2<(sum[x]sum[y])2(sum[i]L)

(sum[x]sum[y]) 除到左边去(因为保证是正数,所以不等号不变,这里 再次强调推公式过程中,要注意 不等式除法改变不等号方向的问题!)
f[x]+sum[x]2f[y]sum[y]2sum[x]sum[y]<2(sum[i]L)

代码

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <algorithm>

#define MAXN 110000

using namespace std;

typedef long long int LL;

int n;
LL L;
LL C[MAXN];
LL sum[MAXN]; //sum[i]=sigma C[j](1<=j<=i)+i
LL f[MAXN];
int q[MAXN],h=1,t=1;

LL fracup(int x,int y)
{
    return (f[y]+sum[y]*sum[y])-(f[x]+sum[x]*sum[x]);
}

LL fracdn(int x,int y) //y>x
{
    return sum[y]-sum[x];
}

int main()
{
    scanf("%d%lld",&n,&L);
    L++;
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&C[i]);
        sum[i]=sum[i-1]+C[i];
    }
    for(int i=1;i<=n;i++) sum[i]+=i;
    q[h]=0;
    for(int i=1;i<=n;i++)
    {
        while(h<t&&fracup(q[h],q[h+1])<2*(sum[i]-L)*fracdn(q[h],q[h+1])) h++;
        f[i]=f[q[h]]+(sum[i]-sum[q[h]]-L)*(sum[i]-sum[q[h]]-L);
        while(h<t&&fracup(q[t-1],q[t])*fracdn(q[t],i)>=fracup(q[t],i)*fracdn(q[t-1],q[t])) t--;
        q[++t]=i;
    }
    printf("%lld\n",f[n]);
    return 0;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

[NOI 2014复习]斜率优化(BZOJ 1096、BZOJ 1010) 的相关文章

  • 删除与获得点数--动态规划

    Leetcode 740 删除与获得点数 题目描述 给定一个整数数组 nums 你可以对它进行一些操作 每次操作中 选择任意一个 nums i 删除它并获得 nums i 的点数 之后 你必须删除每个等于 nums i 1 或 nums i
  • 数学建模常用的四大模型

    目录 1 评价模型 2 优化模型 3 分类模型 4 预测模型 本文主要介绍数学建模的四大模型分类 分别是评价模型 优化模型 分类模型 预测模型 关注公众号 数模乐园 回复 买 获得更多数模教程 1 评价模型 评价模型可以处理难于完全定量分析
  • 国王和金矿问题

    国王和金矿问题 描述 有一个国家发现了max n座金矿 参与挖矿工人的总数是max people人 每座金矿的黄金储量不同为一维数组gold 需要参与挖掘的工人数也不同为一维数组peopleNeed 每座金矿要么全挖 要么不挖 不能派出一半
  • 数字三角形之动态规划(C语言实现)

    算法步骤 1 首先构造三个数组 第一个是存储三角形初始值的数组data 第二个是存储顶点到该点最大值的res 数组 第三个是存储该点上一个点的loc 数组 这里要对res 数组进行初始化 1 2 按照三角形的层次结构 从上到下 从左到右依次
  • 【算法-LeetCode】63. 不同路径 II(动态规划;滚动数组)

    63 不同路径 II 力扣 LeetCode 文章起笔 2021年11月13日16 28 08 问题描述及示例 一个机器人位于一个 m x n 网格的左上角 起始点在下图中标记为 Start 机器人每次只能向下或者向右移动一步 机器人试图达
  • 力扣动态规划专题(一)背包理论基础 基础动规题 动规注意点 步骤及C++实现

    文章目录 动态规划 509 斐波那契数 五步骤 代码 70 爬楼梯 五步骤 代码 746 使用最小花费爬楼梯 五步骤 代码 扩展 62 不同路径 动态规划 数论 63 不同路径 II 五步骤 代码 343 整数拆分 五步骤 代码 96 不同
  • 最近在学动态规划,很有意思的算法(1)拿金币

    问题描述 有一个N x N的方格 每一个格子都有一些金币 只要站在格子里就能拿到里面的金币 你站在最左上角的格子里 每次可以从一个格子走到它右边或下边的格子里 请问如何走才能拿到最多的金币 输入格式 第一行输入一个正整数n 以下n行描述该方
  • OJ刷题---【算法课动态规划] 换硬币(C++完整代码)

    题目 给定面值分别为2 5 7的硬币 每种硬币有无限个 给定一个N 求组成N最少需要的硬币的数量 若无法组成则返回 1 输入 输入N 1 lt N lt 100 输出 输出需要的最少硬币个数 完整代码 C include
  • 【动态规划】从入门到实践---动态规划详解

    目录 1 动态规划概念 一 定义数组元素的含义 二 找到数组元素之间的关系表达式 三 找到初始值 2 案例详解 一 爬楼梯 1 定义数组元素的含义 2 找到数组元素之间的关系表达式 3 找到初始值 案例二 最短路径 题目 做题步骤 1 定义
  • 要求输入月份,判断该月所处的季节并输出季节(假设:12、1、2 月为冬季,依次类推)

    public class Task 10101003 03 public static void main String args Scanner input new Scanner System in System out println
  • 2023华为OD机试真题【星际篮球争霸赛/动态规划】

    题目描述 在星球争霸篮球赛对抗赛中 最大的宇宙战队希望每个人都能拿到MVP MVP的条件是单场最高分得分获得者 可以并列所以宇宙战队决定在比赛中尽可能让更多队员上场 并且让所有得分的选手得分都相同 然而比赛过程中的每1分钟的得分都只能由某一
  • 《算法图解》第九章动态规划学习心得

    1 背包问题 动态规划先解决子问题 再逐步解决大问题 每个动态规划都从一个网格开始 背包问题的网格如下 网格最初是空的 动态规划就是逐步将网格填满 吉他行 第一个单元格表示背包的容量为1磅 吉他的重量也是1磅 这意味着它能装入背包 因此这个
  • 【LeetCode75】第五十九题 第N个泰波那契数

    目录 题目 示例 分析 代码 题目 示例 分析 题目顾名思义 让我们求出第N个泰波那契数 也就是除了开头三个数之外 第四个数开始就是等于前三个数之和 不要和斐波那契数弄混了 斐波那契是前两个数的和 泰波那契是前三个数的和 也就是说当前数 我
  • 3254 Corn Fields 这题解真的不能再详细了!

    题意 农场主John新买了一块长方形的新牧场 这块牧场被划分成 M M M行 N N N列 1
  • [POI2007]砝码Odw

    看这数据范围就不太可DP的样子 考虑贪心 首先注意到题目里有对于任意两个砝码其中一个是另一个质量整数倍的条件 所以砝码质量的种类不超过log INF 考虑按质量从小到大把砝码往容器里放 这样的话所有的砝码和容器的质量都可以除以当前砝码质量然
  • 第14届蓝桥杯C++B组省赛

    文章目录 A 日期统计 B 01 串的熵 C 冶炼金属 D 飞机降落 E 接龙数列 F 岛屿个数 G 子串简写 H 整数删除 I 景区导游 J 砍树 今年比去年难好多 Update 2023 4 10 反转了 炼金二分没写错 可以AC了 U
  • 背包九讲-01背包

    动态规划核心思维能力 动态规划是求最优解问题的重要解法 也是信息学奥赛中每年必考的内容之一 学习动态规划更应该注重此类问题思维能力的锻炼 多多做题 一般 gt 50题后方可入门 注意理解以下概念 1 状态 2 状态属性 3 状态的计算 也就
  • Python之动态规划

    序言 最近在学习python语言 语言有通用性 此文记录复习动态规划并练习python语言 动态规划 Dynamic Programming 动态规划是运筹学的一个分支 是求解决策过程最优化的过程 20世纪50年代初 美国数学家贝尔曼 R
  • acwing算法提高之动态规划--最长上升子序列模型(上)

    目录 1 基础知识 2 模板 3 工程化 1 基础知识 暂无 2 模板 暂无 3 工程化 题目1 怪盗基德的滑翔翼 有N个数 表示房屋的高度 你可以任意选择一个房屋作为起点 选择朝左飞 或者朝右飞 必须严格递减才能够飞到下一个房屋 求经过的
  • 【数位dp】【动态规划】C++算法:233.数字 1 的个数

    作者推荐 动态规划 C 算法312 戳气球 本文涉及的基础知识点 动态规划 数位dp LeetCode 233数字 1 的个数 给定一个整数 n 计算所有小于等于 n 的非负整数中数字 1 出现的个数 示例 1 输入 n 13 输出 6 示

随机推荐