zoukankan      html  css  js  c++  java
  • 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天,你必须卖掉手上的机器。
    求第N+1天后能获得的最大资金。


    $DP-naive$相当好写

    $f[i]$为第$i$天卖掉后最大收益

    $f[i]=max{f[i-1],f[j]-P_j+R_j+G_j*(D_i-D_j-1)}$

    然后变成点斜式

    $f_i=A_j+G_j*D_i$

    $A_j=-D_i*G_j+f_i$

    $(G_j,A_j)$是点,斜率$D_i$正好按时间排序后单调(也就是说本题时间和斜率是一个东西,不用像$cash$那样按斜率排序然后分治里要先按时间分成两块)

    然后$CDQ$分治维护上凸壳就行啦

    fuxey那里学到可以用计算几何那一套来避免精度问题,太棒啦!

    然后我花了两节课调试修改,主要是因为:

    本题的$y$需要加上$f$啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊

    我一开始不考虑$f$结果狂$WA$,然后发现$fuxey$求凸包额外排序了才想到应该加上$f$

    但是复杂度加一个$log$好别扭啊

    于是我把$f$放到归并的比较里,又狂$WA$

    然后发现$f$的下标需要用按时间排序后的下标,又去保存了一个$id$........

    还有一点,要保证$f[j]>P_j$才能买

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    typedef long long ll;
    const int N=1e5+5,INF=1e9;
    inline int read(){
        char c=getchar();int x=0,f=1;
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    struct Vector{
        ll x,y;
        Vector(ll a=0,ll b=0):x(a),y(b){}
    };
    Vector operator -(Vector a,Vector b){return Vector(a.x-b.x,a.y-b.y);}
    typedef Vector Point;
    double Cross(Vector a,Vector b){return (double)a.x*b.y-(double)a.y*b.x;}
    
    int n,D;
    struct Machine{
        int d,p,r,g;
        ll x,y;
        int id;
        void ini(){
            d=read();p=read();r=read();g=read();
            x=g;y=-p+r-(ll)d*g-g;
        }
    }a[N],t[N];
    
    inline bool cmpDay(const Machine &a,const Machine &b){return a.d<b.d;}
    ll f[N];
    inline bool cmp(int i,int j){return a[i].x==a[j].x ? a[i].y+f[a[i].id]<a[j].y+f[a[j].id] : a[i].x<a[j].x;}
    Point p[N],ch[N];
    inline ll line(ll k,Point &p){return k*p.x+p.y;}
    void CDQ(int l,int r){
        if(l==r){f[l]=max(f[l],f[l-1]);return;}
        int mid=(l+r)>>1;
        CDQ(l,mid);
        int n=0,m=0;
        for(int i=l;i<=mid;i++) if(f[a[i].id]>=a[i].p) //!!!!!
            p[++n]=Point(a[i].x,a[i].y+f[a[i].id]);
        for(int i=1;i<=n;i++){
            while(m>1&&Cross(ch[m]-ch[m-1],p[i]-ch[m-1])>=0) m--;
            ch[++m]=p[i];
        }
        int j=1;
        for(int i=mid+1;i<=r;i++){
            while(j<m&&line(a[i].d,ch[j+1])>=line(a[i].d,ch[j])) j++;
            if(j<=m) f[i]=max(f[i],line(a[i].d,ch[j]));
        }
        CDQ(mid+1,r);
    
        int p1=l,p2=mid+1;
        for(int i=l;i<=r;i++){
            if(p2>r||(p1<=mid&&cmp(p1,p2))) t[i]=a[p1++];
            else t[i]=a[p2++];
        }
        for(int i=l;i<=r;i++) a[i]=t[i];
    }
    int main(){
        freopen("in","r",stdin);
        int cas=0;
        while(scanf("%d%lld%d",&n,&f[0],&D)!=EOF){
            if(n==0&&f[0]==0&&D==0) break;
            for(int i=1;i<=n;i++) a[i].ini();
            a[++n].d=D+1;
            sort(a+1,a+1+n,cmpDay);
            for(int i=1;i<=n;i++) a[i].id=i,f[i]=0;
            CDQ(1,n);
            printf("Case %d: %lld
    ",++cas,f[n]);
        }
    }
  • 相关阅读:
    CSS3 渐变 透明 圆角
    使用JSON作为函数的参数(转载)
    如何让输入的单词首字母大写
    mysql 修改表/字段 增加/删除表索引
    Jquery Mobile 客户端验证
    如何写出漂亮的js代码(转载)
    GoogleMap添加一个Marker
    Log4j的使用【转载】
    Google Map 自定义infowindow
    MYSQL重装出现could not start the service mysql error:0处理(已验证可以使用)
  • 原文地址:https://www.cnblogs.com/candy99/p/6441989.html
Copyright © 2011-2022 走看看