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


    【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<=10^5),C是在转型期开始时公司拥有的美元数量(C<=10^9),D是转型期持续的天数(D<=10^9)。
    之后的N行每一行描述了一台机器的情况。每一行有4个正整数Di,Pi,Ri和Gi,分别表示这台机器卖出的时间,购买这台机器需要的美元数量,卖出这台机器的折扣价和使用这台机器可以得到的利润。这些数字满足1<=Di<=D,1<=Ri<Pi<=10^9且1<=Gi<=10^9.
    最后一组测试用例后面的一行由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

    题解:来来来,先列式子:设f[i]表示在还没有买机器i(想买还没买)时,所能得到的最大收益,那么有:

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

    移项搞一搞,感觉像是斜率优化,但是好像x不单调?依旧套用cash那题的做法。上cdq分治,左边按x单调,右边按k单调,用左边更新右边即可。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    const int maxn=100010;
    int n,h,t,T;
    int q[maxn];
    struct node
    {
    	ll P,R,D,G,f;
    }s[maxn],p[maxn];
    ll X(int a)
    {
    	return s[a].G;
    }
    ll Y(int a)
    {
    	return s[a].P-s[a].R+s[a].G+s[a].G*s[a].D-s[a].f;
    }
    int rd()
    {
    	int ret=0,f=1;	char gc=getchar();
    	while(gc<'0'||gc>'9')	{if(gc=='-')f=-f;	gc=getchar();}
    	while(gc>='0'&&gc<='9')	ret=ret*10+gc-'0',gc=getchar();
    	return ret*f;
    }
    bool cmpx(node a,node b)
    {
    	return a.G<b.G;
    }
    bool cmpk(node a,node b)
    {
    	return a.D<b.D;
    }
    long double slope(int a,int b)
    {
    	if(X(a)==X(b))	return (long double)(Y(a)<Y(b)?2147483647:-2147483647);
    	return (long double)(Y(b)-Y(a))/(X(b)-X(a));
    }
    void solve(int l,int r)
    {
    	if(l==r)
    	{
    		s[l].f=max(s[l].f,s[l-1].f);
    		return ;
    	}
    	int mid=l+r>>1,i,h1=l,h2=mid+1;
    	solve(l,mid);
    	h=1,t=0;
    	for(i=l;i<=mid;i++)
    	{
    		if(s[i].f<s[i].P)	continue;
    		while(h<t&&slope(q[t-1],q[t])>=slope(q[t],i))	t--;
    		q[++t]=i;
    	}
    	for(i=mid+1;i<=r;i++)
    	{
    		while(h<t&&slope(q[h],q[h+1])<=s[i].D)	h++;
    		s[i].f=max(s[i].f,s[i-1].f);
    		if(h<=t)	s[i].f=max(s[i].f,s[q[h]].f-s[q[h]].P+s[q[h]].R+s[q[h]].G*(s[i].D-s[q[h]].D-1));
    	}
    	solve(mid+1,r);
    	for(i=l;i<=r;i++)
    	{
    		if(h1<=mid&&(h2>r||X(h1)<=X(h2)))	p[i]=s[h1++];
    		else	p[i]=s[h2++];
    	}
    	for(i=l;i<=r;i++)	s[i]=p[i];
    }
    int main()
    {
    	while(1)
    	{
    		memset(s,0,sizeof(s));
    		n=rd(),s[0].f=rd(),s[n+1].D=rd()+1;
    		if(!n)	return 0;
    		int i;
    		for(i=1;i<=n;i++)	s[i].D=rd(),s[i].P=rd(),s[i].R=rd(),s[i].G=rd();
    		n++;
    		sort(s,s+n+1,cmpk);
    		solve(0,n);
    		sort(s,s+n+1,cmpk);
    		printf("Case %d: %lld
    ",++T,s[n].f);
    	}
    }

     

  • 相关阅读:
    分形之城
    【SDOI2011 第2轮 DAY1】消防 树上问题+二分+贪心
    【Usaco Nov08 Gold】玩具 三分+贪心
    分治 复习
    快读板子
    最小线段覆盖 C神奇项链
    比赛经验积累1
    字符串 专题
    界面小项目之W3C
    前端小基础
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7236399.html
Copyright © 2020-2023  润新知