zoukankan      html  css  js  c++  java
  • BZOJ3963 WF2011MachineWorks(动态规划+斜率优化+cdq分治)

      按卖出时间排序后,设f[i]为买下第i台机器后的当前最大收益,则显然有f[i]=max{f[j]+gj*(di-dj-1)+rj-pi},且若此值<0,应设为-inf以表示无法购买第i台机器。

      考虑优化,显然是一个斜率优化式子,设j转移优于k,则f[j]+gj(di-dj-1)+rj>f[k]+gk(di-dk-1)+rk,移项得(f[j]-gjdj-gj+rj)-(f[k]-gkdk-gk+rk)>di(gk-gj)。g没有单调性,于是cdq分治,按g排序建上凸壳即可。

      注意比较斜率时只能用long double,因为乘法会溢出。对于横坐标相同的点需要特判一下,如果加进去的点纵坐标较大就把之前的点弹掉。感觉每次写斜率优化对这种问题都毫无办法。复杂度O(nlogn)。

    #include<iostream> 
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define ll long long
    #define N 100010
    #define inf 2000000000000000000ll
    char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
    int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
    int read()
    {
        int x=0,f=1;char c=getchar();
        while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
        while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        return x*f;
    }
    int T,n,m,k,q[N];
    struct data
    {
        int d,p,r,g,i;ll ans;
        bool operator <(const data&a) const
        {
            return d<a.d;
        }
    }a[N],b[N];
    ll calc(int i){return a[i].ans-1ll*a[i].g*(a[i].d+1)+a[i].r;}
    bool check(int x,int y,int i)
    {
        if (a[i].g==a[y].g) return calc(i)>=calc(y);
        return (long double)(calc(i)-calc(y))/(a[i].g-a[y].g)>=(long double)(calc(y)-calc(x))/(a[y].g-a[x].g);
    }
    void solve(int l,int r)
    {
        if (l>=r) return;
        int mid=l+r>>1;
        solve(l,mid);
        int head=1,tail=0;
        for (int i=l;i<=mid;i++)
        {
            while (tail>1&&check(q[tail-1],q[tail],i)) tail--;
            q[++tail]=i;
        }
        for (int i=mid+1;i<=r;i++)
        {
            while (head<tail&&calc(q[head+1])-calc(q[head])>-1ll*a[i].d*(a[q[head+1]].g-a[q[head]].g)) head++;
            if (calc(q[head])+1ll*a[q[head]].g*a[i].d-a[i].p>=0)
            a[i].ans=max(a[i].ans,calc(q[head])+1ll*a[q[head]].g*a[i].d-a[i].p);
        }
        solve(mid+1,r);
        int i=l,j=mid+1;
        for (int k=l;k<=r;k++)
        if (i<=mid&&a[i].g<a[j].g||j>r) b[k]=a[i++];
        else b[k]=a[j++];
        for (int k=l;k<=r;k++) a[k]=b[k];
    }
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("bzoj3963.in","r",stdin);
        freopen("bzoj3963.out","w",stdout);
        const char LL[]="%I64d
    ";
    #else
        const char LL[]="%lld
    ";
    #endif
        n=read(),m=read(),k=read();
        while (n)
        {
            for (int i=1;i<=n;i++) a[i].d=read(),a[i].p=read(),a[i].r=read(),a[i].g=read(),a[i].i=i;
            n++,a[n].d=k+1,a[n].p=a[n].r=a[n].g=0;
            sort(a+1,a+n+1);
            for (int i=1;i<=n;i++) a[i].ans=-inf;a[0].ans=m;
            solve(0,n);
            for (int i=1;i<=n;i++) a[0].ans=max(a[0].ans,a[i].ans);
            printf("Case ");printf("%d",++T);printf(": ");printf(LL,a[0].ans);
            n=read(),m=read(),k=read();
        }
        return 0;
    }
  • 相关阅读:
    JDK1.5新特性,基础类库篇,调用外部命令类(ProcessBuilder)用法
    JDK1.5新特性,基础类库篇,格式化类(Formatter)用法
    JDK1.5新特性,语言篇
    几种常见排序算法之Java实现(插入排序、希尔排序、冒泡排序、快速排序、选择排序、归并排序)
    JSON概述及其在JavaScript与Java中的应用(整理)
    JavaScript:表单常用验证脚本(整理)
    JavaScript:零星知识
    浏览器脚本概述(整理)
    Angular
    Angular
  • 原文地址:https://www.cnblogs.com/Gloid/p/10269853.html
Copyright © 2011-2022 走看看