HDU 3842 Machine Works cdq分治 斜率优化

本题是利用cdq分治  实现斜率优化的一个题目

斜率优化之前做的几个题都是斜率单调,并且插入点时由于点在某一维单调,所以仅仅操作队首和队尾就能完成优化了

但是本题显然不是

主要参考了两个东西

从《Cash》谈一类分治算法的应用

(Day1)cdq分治相关

这两个直接在百度上搜 ,第一个出来的就是

本题的题意是

一个公司获得了一个厂房n(10^5)天的使用权

和一笔启动资金C(10^9),准备在n天里租借机器生产来获得收益

可以租借的机器有M(10^5)个,每个机器有四个值,D,P,R,G (D<=n, P,R,G都是10^9)

表明你可以再第D天花费P费用(首先手里必须有那么多钱)

租借这个机器,从D+1天开始该机器每天产生G的收益,在你不需要机器时

可以卖掉这个机器,一次获得R的钱

需要注意的是:

厂房里只能停留一台机器

不能再购买和卖出机器的那天操作机器,但是可以再同一天卖掉一台机器再买一台

在第n+1天,必须卖掉手里的机器

问n+1天后能获得的最大资金

根据这个题意

我们可以得到一个dp转移方程

首先要想的问题是是否有场地就要放机器

最开始的时候肯定不是这样,因为怕买到坑的机器很可能会亏钱,但是假设你买到了一台好的机器,在下一个机器进来之前,你肯定是一直运转下去的

然后得把所有的时间都离散化,就是每个机器的D

然后用f[i]表示在D[i]时刻卖掉手里的机器手里最多多少钱

f[i] = max(f[i - 1], f[j] - P[j] + R[j] + G[j] * (D[i] - D[j]  - 1))

其中f[j] >= P[j]

可以看出是O(n^2)的,显然不行啊

令h[j] = f[j] + R[j]- P[j] - G[j] * (D[j] + 1)

式子就变成  f[i] = h[j] + D[i] * G[j]

即h[j] = -D[i] * G[j] + f[i]

对于这个, 可以抽象成一个二维空间

由(G[j],h[j])作为点集, -D[i]为斜率

然后求使得截距最大的那个,就是f[i]最大了

观察这些点集

可以发现,一点都不单调啊,就需要按照G[j]这一维做个排序

使得他至少在一维上单调,方便我们做插入和删除操作

然后由于斜率是单调递减的,并且是负数

可以画一画,最后要维护的最优点的点集,在图上形成的是一条上凸的线

然后每插一个点都是维护这个图形

然后这个排序,你在普通的DP方法里肯定是不能每次都去排序的

这就需要cdq分治了

对于一个区间l,r

你先更新了l,mid

然后对左边这部分的区间的点集, 进行排序,形成上面这个图形

然后更新右边区间的时候,

由于斜率是递减的,你可以发现,我们只需要扫一遍这个图形即可完成所有右边区间值的更新

然后就这样递归着去更新

完成cdq分治

总体复杂度,应该是nlognlogn

因为每个子区间中都有这个排序

代码还是参照xiaodao的,因为实在是不熟悉这个方法。

需要留意的是,在斜率之间做比较的时候,如果用乘法来比较的话,会溢出long long

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <ctime>
#include <set>
#include <vector>
#include <map>
#define MAXN 11111
#define MAXM 55555
#define INF 1000000007
using namespace std;
long long f[111111];
struct node {
    int d, p, g, r;
}p[111111];
bool cmp(node x, node y) {
    return x.d < y.d;
}
int n, d;
typedef pair<int, long long> PA;
PA A[111111], C[111111];
long long h(int j) {
    return f[j] + (long long)p[j].r - (long long)p[j].p - (long long)p[j].g * (long long)(p[j].d + 1);
}
int slopecomp(PA a, PA b, PA c) {
    long long xa = b.first - a.first;
    long long xb = c.first - a.first;
    long long ya = b.second - a.second;
    long long yb = c.second - a.second;
    double tmp = (double)xa * yb - (double)xb * ya;
    return tmp < 0;
}
void cdq(int l, int r) {
    if(l + 1 < r) {
        int m = (l + r) >> 1;
        cdq(l, m);
        int na = 0, nb = 0, nc = 0;
        for(int j = l; j < m; j++) {
            if(f[j] >= p[j].p) A[na++] = PA(p[j].g, h(j));
        }
        sort(A, A + na);
        for(int i = 0; i < na; i++) {
            while(nc > 1 && !slopecomp(C[nc - 1], C[nc], A[i])) nc--;
            C[++nc] = A[i];
        }
        int j = 0;
        for(int i = m; i < r; i++) {
            long long a1, a2, b1, b2, x;
            x = p[i].d;
            while(j < nc) {
                a1 = C[j].first;
                a2 = C[j + 1].first;
                b1 = C[j].second;
                b2 = C[j + 1].second;
                if(a1 * x + b1 >= a2 * x + b2) break;
                j++;
            }
            f[i] = max(f[i], (long long)C[j].first * x + C[j].second);
        }

        cdq(m, r);
    }
}
int main() {
    int cas = 0;
    while(scanf("%d%I64d%d", &n, &f[0], &d) != EOF) {
        if(n == 0 && f[0] == 0 && d == 0) break;
        for(int i = 1; i <= n; i++) scanf("%d%d%d%d", &p[i].d, &p[i].p, &p[i].r, &p[i].g);
        sort(p + 1, p + n + 1, cmp);
        ++n;
        p[n].d = d + 1;
        p[n].g = p[n].p = 0;
        for(int i = 1; i <= n; i++) f[i] = f[0];
        cdq(0, n + 1);
        printf("Case %d: %I64d\n", ++cas, f[n]);
    }
    return 0;
}
时间: 2024-08-06 20:07:33

HDU 3842 Machine Works cdq分治 斜率优化的相关文章

【uoj#244】[UER #7]短路 CDQ分治+斜率优化dp

题目描述 给出 $(2n+1)\times (2n+1)$ 个点,点 $(i,j)$ 的权值为 $a[max(|i-n-1|,|j-n-1|)]$ ,找一条从 $(1,1)$ 走到 $(2n+1,2n+1)$ 的路径,使得经过的点(包括起点和终点)权值和最小.求这个权值和. 输入 第一行一个正整数 $n$ . 第二行 $n+1$ 个正整数 $a[0],a[1],…,a[n]$ ,表示从内到外每层的中继器的延时值. 输出 输出一行一个数表示改造后的最短引爆时间. 样例输入 99 5 3 7 6 9

BZOJ 3963: [WF2011]MachineWorks [CDQ分治 斜率优化DP]

传送门 当然了WF的题uva hdu上也有 你的公司获得了一个厂房N天的使用权和一笔启动资金,你打算在这N天里租借机器进行生产来获得收益.可以租借的机器有M台.每台机器有四个参数D,P,R,G.你可以在第D天花费P的费用(当然,前提是你有至少P元)租借这台机器,从第D+1天起,操作机器将为你产生每天G的收益.在你不再需要机器时,可以将机器卖掉,一次性获得R的收益.厂房里只能停留一台机器.不能在购买和卖出机器的那天操作机器,但是可以在同一天卖掉一台机器再买入一台.在第N+1天,你必须卖掉手上的机器

【BZOJ3963】[WF2011]MachineWorks cdq分治+斜率优化

[BZOJ3963][WF2011]MachineWorks Description 你是任意性复杂机器公司(Arbitrarily Complex Machines, ACM)的经理,公司使用更加先进的机械设备生产先进的机器.原来的那一台生产机器已经坏了,所以你要去为公司买一台新的生产机器.你的任务是在转型期内尽可能得到更大的收益.在这段时间内,你要买卖机器,并且当机器被ACM公司拥有的时候,操控这些机器以获取利润.因为空间的限制,ACM公司在任何时候都只能最多拥有一台机器. 在转型期内,有若

BZOJ 1492 NOI 2007 货币兑换Cash CDQ分治+斜率优化DP

题目大意:有两种金券,A和B.每一天有一个rate值,表示购入的比例:还有每一天AB金券的售价.现在给出初始的钱数,问最后能够获得多少钱. 思路:这算是神题了吧,啃论文啃别人代码将近一天才算有点明白. 首先题目中说的可以买一部分或者卖一部分是扯淡的,因为为了最大获利一定要全部买入,全部卖出.朴素的DP方程就好弄了. 设f[i]为第i天最多的B券的数量.那么f[i] = (rate[j] * f[j] * a[i] + f[j] * b[i]) / (rate[i] * a[i] + b[i])

bzoj1492[NOI2007]货币兑换Cash cdq分治+斜率优化dp

1492: [NOI2007]货币兑换Cash Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 5541  Solved: 2228[Submit][Status][Discuss] Description 小Y最近在一家金券交易所工作.该金券交易所只发行交易两种金券:A纪念券(以下简称A券)和 B纪念券(以下 简称B券).每个持有金券的顾客都有一个自己的帐户.金券的数目可以是一个实数.每天随着市场的起伏波动, 两种金券都有自己当时的价值,即每一单位金

bzoj3672/luogu2305 购票 (运用点分治思想的树上cdq分治+斜率优化dp)

我们都做过一道题(?)货币兑换,是用cdq分治来解决不单调的斜率优化 现在它放到了树上.. 总之先写下来dp方程,$f[i]=min\{f[j]+(dis[i]-dis[j])*p[i]+q[i]\} ,j是i的祖先,dis[i]-dis[j]<=l[i]$ ,其中dis[i]表示1号点到i号点的距离 可以很明显的看出斜率优化,但我们要放到树上做 于是就运用点分治的思想来找重心(正如普通的cdq是找重点一样) 步骤是这样的: 1.对于根为x的一个子树,我们先找到它的重心rt 2.把rt的子树刨掉

[BZOJ 1492][NOI2007]货币兑换Cash(CDQ分治+斜率优化Dp)

Description 小Y最近在一家金券交易所工作.该金券交易所只发行交易两种金券:A纪念券(以下简称A券)和 B纪念券(以下 简称B券).每个持有金券的顾客都有一个自己的帐户.金券的数目可以是一个实数.每天随着市场的起伏波动, 两种金券都有自己当时的价值,即每一单位金券当天可以兑换的人民币数目.我们记录第 K 天中 A券 和 B券 的 价值分别为 AK 和 BK(元/单位金券).为了方便顾客,金券交易所提供了一种非常方便的交易方式:比例交易法 .比例交易法分为两个方面:(a)卖出金券:顾客提

【CDQ】HDU 3842 Machine Works

通道 题意: 一个公司获得了一个厂房n(10^5)天的使用权和一笔启动资金C(10^9),准备在n天里租借机器生产来获得收益可以租借的机器有M(10^5)个,每个机器有四个值,D,P,R,G (D<=n, P,R,G都是10^9)表明你可以再第D天花费P费用(首先手里必须有那么多钱)租借这个机器,从D+1天开始该机器每天产生G的收益,在你不需要机器时可以卖掉这个机器,一次获得R的钱 思路: 用f[i]表示在D[i]时刻卖掉手里的机器手里最多多少钱 f[i] = max(f[i - 1], f[j

bzoj [NOI2007]货币兑换Cash (cdq分治+斜率优化 )

1492: [NOI2007]货币兑换Cash Time Limit: 5 Sec  Memory Limit: 64 MB Submit: 2454  Solved: 1078 [Submit][Status][Discuss] Description Input 第一行两个正整数N.S,分别表示小Y 能预知的天数以及初始时拥有的钱数. 接下来N 行,第K 行三个实数AK.BK.RateK,意义如题目中所述 Output 只有一个实数MaxProfit,表示第N 天的操作结束时能够获得的最大的