P2120 [ZJOI2007]仓库建设 斜率优化dp

好题,这题是我理解的第一道斜率优化dp,自然要写一发题解。首先我们要写出普通的表达式,然后先用前缀和优化。然后呢?我们观察发现,x【i】是递增,而我们发现的斜率也是需要是递增的,然后就维护一个单调递增就行了。

放一个证明题解。

设f[i]表示在i点建仓库的最小费用,易得方程:f[i]=min(f[j]+(x[i]-x[j+1])*p[j+1]+(x[i]-x[j+1])*p[j+2]...) =min(f[j]+c[i]+x[i]*(p[j+1..i])-(x[j+1]*p[j+1]+...+x[i]*p[i]))

设s[i]=p[1]+p[2]+..p[i],ss[i]=x[1]*p[1]+...x[i]*p[i]
f[i]=f[j]+c[i]+x[i]*(s[i]-s[j])-(ss[i]-ss[j])

设j<k即s[j]<s[k],当取k更优时满足:
f[j]+x[i]*(s[i]-s[j])+ss[j]>f[k]+x[i]*(s[i]-s[k])+ss[k]
x[i]>(f[k]-f[j]+ss[k]-ss[j])/(s[k]-s[j])

设x<y<z,cale(i,j)表示i、j间的斜率
若cale(x,y)>cale(y,z)
 1.x[i]>cale(x,y)>cale(y,z)则z更优
 2.x[i]<cale(x,y),则x更优
因为x[i]递增,情况1保持不变,情况2可能会变成情况1还是不可能取y
综上当cale(x,y)>cale(y,z)时可以踢掉y,即维护斜率递增题干:
题目背景

小B的班级数学学到多项式乘法了,于是小B给大家出了个问题:用编程序来解决多项式乘法的问题。
题目描述

L公司有N个工厂,由高到底分布在一座山上。

工厂1在山顶,工厂N在山脚。 由于这座山处于高原内陆地区(干燥少雨),L公司一般把产品直接堆放在露天,以节省费用。

突然有一天,L公司的总裁L先生接到气象部门的电话,被告知三天之后将有一场暴雨,于是L先生决定紧急在某些工厂建立一些仓库以免产品被淋坏。

由于地形的不同,在不同工厂建立仓库的费用可能是不同的。第i个工厂目前已有成品Pi件,在第i个工厂位置建立仓库的费用是Ci。

对于没有建立仓库的工厂,其产品应被运往其他的仓库进行储藏,而由于L公司产品的对外销售处设置在山脚的工厂N,故产品只能往山下运(即只能运往编号更大的工厂的仓库),当然运送产品也是需要费用的,假设一件产品运送1个单位距离的费用是1。

假设建立的仓库容量都都是足够大的,可以容下所有的产品。你将得到以下数据:

    工厂i距离工厂1的距离Xi(其中X1=0);
    工厂i目前已有成品数量Pi;
    在工厂i建立仓库的费用Ci;

请你帮助L公司寻找一个仓库建设的方案,使得总的费用(建造费用+运输费用)最小。
输入输出格式
输入格式:

第一行包含一个整数N,表示工厂的个数。接下来N行每行包含两个整数Xi, Pi, Ci, 意义如题中所述。

输出格式:

仅包含一个整数,为可以找到最优方案的费用。

代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<ctime>
#include<queue>
#include<algorithm>
#include<cstring>
using namespace std;
#define duke(i,a,n) for(register int i = a;i <= n;i++)
#define lv(i,a,n) for(register int i = a;i >= n;i--)
#define clean(a) memset(a,0,sizeof(a))
const int INF = 1 << 30;
typedef long long ll;
typedef double db;
template <class T>
void read(T &x)
{
    char c;
    bool op = 0;
    while(c = getchar(), c < ‘0‘ || c > ‘9‘)
        if(c == ‘-‘) op = 1;
    x = c - ‘0‘;
    while(c = getchar(), c >= ‘0‘ && c <= ‘9‘)
        x = x * 10 + c - ‘0‘;
    if(op) x = -x;
}
template <class T>
void write(T x)
{
    if(x < 0) putchar(‘-‘), x = -x;
    if(x >= 10) write(x / 10);
    putchar(‘0‘ + x % 10);
}
const int N = 1e6 + 5;
int n,m,x[N],q[N],c[N];
ll f[N],ss[N],s[N];
db calc(int j,int k)
{
    return (f[k] - f[j] + ss[k] - ss[j]) * 1.0 / (s[k] - s[j]);
}
int main()
{
    read(n);
    duke(i,1,n)
    {
        read(x[i]);read(s[i]);read(c[i]);
        ss[i] = ss[i - 1] + x[i] * s[i];
        s[i] += s[i - 1];
    }
    for(int i = 1,l = 0,r = 0;i <= n;i++)
    {
        while(l < r && x[i] > calc(q[l],q[l + 1])) l++;
        f[i] = f[q[l]] + c[i] - ss[i] + ss[q[l]] + x[i] * (s[i] - s[q[l]]);
        while(l < r && calc(q[r - 1],q[r]) > calc(q[r],i)) r--;
        q[++r] = i;
    }
    printf("%lld\n",f[n]);
    return 0;
} 
 

原文地址:https://www.cnblogs.com/DukeLv/p/10099533.html

时间: 2024-08-16 17:05:02

P2120 [ZJOI2007]仓库建设 斜率优化dp的相关文章

bzoj-1096 1096: [ZJOI2007]仓库建设(斜率优化dp)

题目链接: 1096: [ZJOI2007]仓库建设 Description L公司有N个工厂,由高到底分布在一座山上.如图所示,工厂1在山顶,工厂N在山脚.由于这座山处于高原内陆地区(干燥少雨),L公司一般把产品直接堆放在露天,以节省费用.突然有一天,L公司的总裁L先生接到气象部门的电话,被告知三天之后将有一场暴雨,于是L先生决定紧急在某些工厂建立一些仓库以免产品被淋坏.由于地形的不同,在不同工厂建立仓库的费用可能是不同的.第i个工厂目前已有成品Pi件,在第i个工厂位置建立仓库的费用是Ci.对

BZOJ 1096 [ZJOI2007]仓库建设 斜率优化dp

1096: [ZJOI2007]仓库建设 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/problem.php?id=1096 Description L公司有N个工厂,由高到底分布在一座山上.如图所示,工厂1在山顶,工厂N在山脚. 由于这座山处于高原内陆地区(干燥少雨),L公司一般把产品直接堆放在露天,以节省费用.突然有一天,L公司的总裁L先生接到气象部门的电话,被告知三天之后将有一场

[BZOJ1096] [ZJOI2007] 仓库建设 (斜率优化dp)

Description L公司有N个工厂,由高到底分布在一座山上.如图所示,工厂1在山顶,工厂N在山脚.由于这座山处于高原内陆地区(干燥少雨),L公司一般把产品直接堆放在露天,以节省费用.突然有一天,L公司的总裁L先生接到气象部门的电话,被告知三天之后将有一场暴雨,于是L先生决定紧急在某些工厂建立一些仓库以免产品被淋坏.由于地形的不同,在不同工厂建立仓库的费用可能是不同的.第i个工厂目前已有成品Pi件,在第i个工厂位置建立仓库的费用是Ci.对于没有建立仓库的工厂,其产品应被运往其他的仓库进行储藏

【BZOJ-1096】仓库建设 斜率优化DP

1096: [ZJOI2007]仓库建设 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 3719  Solved: 1633[Submit][Status][Discuss] Description L公司有N个工厂,由高到底分布在一座山上.如图所示,工厂1在山顶,工厂N在山脚.由于这座山处于高原内陆地区(干燥少雨),L公司一般把产品直接堆放在露天,以节省费用.突然有一天,L公司的总裁L先生接到气象部门的电话,被告知三天之后将有一场暴雨,于是L先

BZOJ 1096 ZJOI2007 仓库设计 斜率优化dp

太高兴了,这是我第一次自己独立思考的斜率优化dp,从头到尾都是自己想的.(相信自己,能行的,不过也做了40分钟了). 这道题目还好吧! 看到之后第一反应是想设从工厂0运到工厂i 总共需要 tot[i] 的费用, 用 p[i] 表示从山顶到工厂 i 总共的产品数, 再用 x[i] 表示从工厂0到工厂 i 的距离, 那么状态转移方程就是 f[i] = min{f[j] + tot[i] - tot[j] - p[j] * (x[i] - x[j] ) + c[i] } ,很明显由于数据有 n <=

[ZJOI2007]仓库建设(斜率优化)

L公司有N个工厂,由高到底分布在一座山上. 工厂1在山顶,工厂N在山脚. 由于这座山处于高原内陆地区(干燥少雨),L公司一般把产品直接堆放在露天,以节省费用. 突然有一天,L公司的总裁L先生接到气象部门的电话,被告知三天之后将有一场暴雨,于是L先生决定紧急在某些工厂建立一些仓库以免产品被淋坏. 由于地形的不同,在不同工厂建立仓库的费用可能是不同的.第i个工厂目前已有成品Pi件,在第i个工厂位置建立仓库的费用是Ci. 对于没有建立仓库的工厂,其产品应被运往其他的仓库进行储藏,而由于L公司产品的对外

[Bzoj1096][ZJOI2007]仓库建设(斜率优化)

题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1096 一开始想了想费用流,然后被数据范围pass掉了,感觉dp更可行一些. 只想到一个O(n2)的做法,看到式子比较复杂,就感觉像是斜率优化. dp[i]表示前i个工厂所求的最小费用,则第i个工厂一定会建一个仓库.转移方程为$dp[i]=min(dp[j]+\sum_{k=j}^{i-1}p[k]*(x[i]-x[k]))+c[i]$. 将式子展开,用sump表示p数组的前缀和,sum

BZOJ 1096 ZJOI2007 仓库建设 斜率优化

题目大意:给定n个厂房,在其中一些建仓库,一个点如果没有仓库就要把仓库运到右侧的仓库中,求最小花销 很简单的斜率优化--之前刷斜率优化的时候怎么居然把这道题漏了 令f[i]为在i点建厂使i之前的货物全部安置的最小花销 则有 公式编辑器就是爽啊~ 令sump[i]为p[i]的前缀和 令sumxp[i]为p[i]*x[i]的前缀和 化简有 f[j] + sumxp[j] = x[i]*sump[j] + sumxp[i] - x[i]*sump[i] - C[i] + f[i] 其中 X[j]=su

【1096】【ZJOI2007】仓库建设 斜率优化DP

呃,不难,什么方程都在注释里面. <span style="font-family:KaiTi_GB2312;font-size:18px;">#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define N 1001000 #define inf 0x3f3f3f3f /* f[i]=f[j]+sum[i]-sum[