• BZOJ3963: [WF2011]MachineWorks 【CDQ+斜率优化DP】*


    BZOJ3963: [WF2011]MachineWorks


    Description

    你是任意性复杂机器公司(Arbitrarily Complex Machines, ACM)的经理,公司使用更加先进的机械设备生产先进的机器。原来的那一台生产机器已经坏了,所以你要去为公司买一台新的生产机器。你的任务是在转型期内尽可能得到更大的收益。在这段时间内,你要买卖机器,并且当机器被ACM公司拥有的时候,操控这些机器以获取利润。因为空间的限制,ACM公司在任何时候都只能最多拥有一台机器。
    在转型期内,有若干台可能卖出的机器。作为先进机器的专家,对于每台机器Mi,你已经知道了其价格Pi和可以买入的日期Di。注意,如果不在第Di天买入机器Mi,那么别的人也会买走这一台机器,也就是说,以后你将没有机会购买这台机器了。如果ACM的钱低于一台机器的价格,那么你显然不可能买到这一台机器。
    如果你在第Di天买入了机器Mi,那么ACM公司可以从第(Di)+1天开始使用这一台机器。每使用这台机器一天,就可以为公司创造出Gi美元的收益。
    你可以决定要在买入之后的某一天,以一定的折扣价卖出这一台机器。收购市场对于每一台机器,都有一个折扣价Ri。你不能在卖出的那一天使用机器,但是你可以在卖出的那一天再买入一台新的。
    在转型期结束后,ACM公司会卖掉当前所拥有的机器。你的任务就是最大化转型期间ACM公司可以得到的收入。

    Input

    输入包含若干组测试用例。每一组测试用例的第一行有3个正整数N,C和D。N是将会卖出的机器的台数(N&lt;=105)(N&lt;=10^5)(N<=105),C是在转型期开始时公司拥有的美元数量(C&lt;=109)(C&lt;=10^9)(C<=109),D是转型期持续的天数(D&lt;=109)(D&lt;=10^9)(D<=109)
    之后的N行每一行描述了一台机器的情况。每一行有4个正整数Di,Pi,Ri和Gi,分别表示这台机器卖出的时间,购买这台机器需要的美元数量,卖出这台机器的折扣价和使用这台机器可以得到的利润。这些数字满足1&lt;=Di&lt;=D,1&lt;=Ri&lt;Pi&lt;=1091&lt;=Di&lt;=D,1&lt;=Ri&lt;Pi&lt;=10^91<=Di<=D,1<=Ri<Pi<=1091&lt;=Gi&lt;=1091&lt;=Gi&lt;=10^91<=Gi<=109.
    最后一组测试用例后面的一行由3个0组成,表示输入数据。

    Output

    对于每一组测试用例,输出测试用例的编号,之后给出ACM公司在第D+1天结束后可以得到的最大数量的美元。
    请依照下面给出的样例输出。

    Sample Input

    6 10 20
    6 12 1 3
    1 9 1 2
    3 2 1 2
    8 20 5 4
    4 11 7 4
    2 10 9 1
    0 0 0

    Sample Output

    Case 1: 44


    比较裸的CDQ+斜率优化吧

    直接维护就行了?

    首先定义一下DP:dpidp_idpi表示卖完第i台机器的最大收益,也就是卖出上一台机器的收益-pip_ipi

    然后考虑转移dpi=max(dpj+rj+(di−dj−1)∗dj)−pidp_i=max(dp_j+r_j+(d_i-d_j-1)*d_j)-p_idpi=max(dpj+rj+(didj1)dj)pi
    把中间展开dpi=dpj+rj−(dj+1)∗gj+di∗gj−pidp_i=dp_j+r_j-(d_j+1)*g_j+d_i*g_j-p_idpi=dpj+rj(dj+1)gj+digjpi
    然后变成点斜式dpi+pi−di∗gj=dpj+dj−(dj+1)∗gjdp_i+p_i-d_i*g_j=dp_j+d_j-(d_j+1)*g_jdpi+pidigj=dpj+dj(dj+1)gj
    然后我们只需要判断一下可不可行dpi&gt;pidp_i&gt;p_idpi>pi然后直接CDQ分治,用左边的维护凸包,然后将右边的斜率排一下序直接查找就好了

    不想写归并所以就直接sort了,多个log影响不大


     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define LL long long
     4 #define pi pair<LL,LL>
     5 #define N 100010
     6 #define INFF 1e16
     7 #define INFI 0x3f3f3f3f3f3f3f3f
     8 LL n,m,c;
     9 LL dp[N];//买入机器i之后的最大收益
    10 struct Machine{
    11     LL d,p,r,g;
    12     void init(){scanf("%lld%lld%lld%lld",&d,&p,&r,&g);}
    13 }t[N];
    14 struct Node{
    15     LL x,y;
    16     Node(){}
    17     Node(int id){
    18         x=t[id].g;
    19         y=dp[id]+t[id].r-t[id].g*(t[id].d+1);
    20     }
    21     Node(LL _x,LL _y){x=_x,y=_y;}
    22 };
    23 vector<Node> lq,rq;
    24 deque<Node> q;
    25 bool cmpMachine(Machine a,Machine b){return a.d<b.d;}
    26 bool cmpNode(Node a,Node b){
    27     if(a.x==b.x)return a.y<b.y;
    28     return a.x<b.x;
    29 }
    30 double getk(Node a,Node b){
    31     if(a.x==b.x)return INFF;
    32     return (double) (a.y-b.y)/(double) (a.x-b.x);
    33 }
    34 void solve(int l,int r){
    35     if(l==r){
    36         dp[l]=max(dp[l],1ll*c);dp[l]-=t[l].p;
    37         if(dp[l]<0)dp[l]=-INFI;
    38         return;
    39     }
    40     int mid=(l+r)>>1;
    41     solve(l,mid);
    42     lq.clear();rq.clear();q.clear();
    43     for(int i=l;i<=mid;i++)if(dp[i]!=-INFI)lq.push_back(Node(i));
    44     for(int i=mid+1;i<=r;i++)rq.push_back(Node(t[i].d,i));
    45     sort(lq.begin(),lq.end(),cmpNode);
    46     sort(rq.begin(),rq.end(),cmpNode);
    47     for(int i=0;i<lq.size();i++){
    48         while(q.size()>=2&&getk(lq[i],q.back())>getk(q.back(),q[q.size()-2]))q.pop_back();
    49         q.push_back(lq[i]);
    50     }
    51     if(q.size()){
    52         for(int i=0;i<rq.size();i++){
    53             while(q.size()>=2&&getk(q[0],q[1])>-rq[i].x)q.pop_front();
    54             dp[rq[i].y]=max(dp[rq[i].y],q.front().x*rq[i].x+q.front().y);
    55         }
    56     }
    57     solve(mid+1,r);
    58 }
    59 int main(){
    60     int T=0;
    61     while(scanf("%lld%lld%lld",&m,&c,&n)&&(n||m||c)){
    62         for(int i=1;i<=m;i++)t[i].init(),dp[i]=-INFI;
    63         t[++m]=(Machine){n+1,0,0,0};dp[m]=-INFI;
    64         sort(t+1,t+m+1,cmpMachine);
    65         solve(1,m);
    66         printf("Case %d: %lld
    ",++T,dp[m]);
    67     }
    68     return 0;
    69 }
  • 相关阅读:
    黑客工具包ShadowBrokers浅析
    浅谈Miller-Rabin素数检测算法
    辗转相除法(欧几里得算法)的证明
    2019年年终感言
    详解矩阵乘法
    计数类问题中的取模运算总结
    浅谈同余方程的求解与中国剩余定理
    模板测试题
    洛谷 P3811 【模板】乘法逆元
    同余知识点全析
  • 原文地址:https://www.cnblogs.com/dream-maker-yk/p/9676269.html
Copyright © 2020-2023  润新知