2017.9.26 货币兑换 失败总结

这个题首先要注意到提示:全买全卖,,不然很容易误入歧途

然后可以根据确定性n^2 dp,,由于它是全买全卖,所以枚举上一个买入的点在哪里,算全卖出的价值取max

     如果这个点不卖,则它一定有钱,所以继承前面最大的钱取max,

    然后考虑在这个点卖,由于a:b是定值,钱和数量是直接相关的  所以只记录一个b的数量即可


f【i】=max(f【i-1】,A【j】*fa【i】+B【j】*fb【i】)

用斜率优化的方式化式子:

-A【j】=fa【i】/ fb【i】 *B【j】*rate【j】  -  f【i】/fb【i】

    y       =          k                          x                 +             b

注意正负号,第一次式子写错了调了2h、


然后就需要x、k的单调性,就可以用cdq分治

对左区间操作     对整体操作      对右区间操作    ←顺序非常重要

由于y是负值   ,b是负值   ,  f【i】∝  -b

所以要让-b最大,  b就要最小

由于x、k单增,所以最优点一定在下凸包上

所以左区间按x排序  右区间按k排序,转移即可

注意排完之后要按时间顺序还原


复杂度  o(nlog^2n)


码(常数巨大,超时卡过):

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
double ans;
int n,m,i,j,k,q[100005],s;
struct tian
{
	double fa,fb,id,R,k,B,f;
}d[100005];
bool cmp1(tian a,tian b)
{
	return a.id<b.id;	
}
bool cmp2(tian a,tian b)
{
	return a.B*a.R<b.B*b.R;	
}
bool cmp3(tian a,tian b)
{
	return a.fa/a.fb<b.fa/b.fb;	
}
double xl(int a,int b)
{
	return (-d[a].B+d[b].B)/(d[a].B*d[a].R-d[b].B*d[b].R);
}
void cdq(int l,int r)
{
	if(l==r)
	{
		if(d[l].f<d[l-1].f)
		{
			d[l].f=d[l-1].f;
			d[l].B=d[l].f/(d[l].R*d[l].fa+d[l].fb);
		}	
	return;
}
	int mid=(l+r)>>1;
cdq(l,mid);
for(i=l;i<=mid;i++)
	if(d[i].f<d[i-1].f)
		{
			d[i].f=d[i-1].f;
			d[i].B=d[i].f/(d[i].R*d[i].fa+d[i].fb);
		}
sort(d+l,d+mid+1,cmp2);
sort(d+mid+1,d+r+1,cmp3);
int z1=1,z2=0;
	for(i=l;i<=mid;i++)
	{
		while(z1<z2&&xl(q[z2-1],i)>=xl(q[z2],i))z2--;
		q[++z2]=i;
	}
	for(i=mid+1;i<=r;i++)
	{
		while(z1<z2&&d[q[z1]].B*d[i].fb+d[q[z1]].B*d[q[z1]].R*d[i].fa<=d[q[z1+1]].B*d[i].fb+d[q[z1+1]].B*d[q[z1+1]].R*d[i].fa)z1++;
		if(d[i].f<d[q[z1]].B*d[i].fb+d[q[z1]].B*d[q[z1]].R*d[i].fa)
		{
		d[i].f=d[q[z1]].B*d[i].fb+d[q[z1]].B*d[q[z1]].R*d[i].fa;
		d[i].B=d[i].f/(d[i].R*d[i].fa+d[i].fb);	
		}
	}
sort(d+l,d+mid+1,cmp1);
sort(d+mid+1,d+r+1,cmp1);
//消除影响,按实际安排			
cdq(mid+1,r);	
}
int main()
{
	scanf("%d%d",&n,&s);
d[0].f=s;
	for(i=1;i<=n;i++)
	{
		scanf("%lf%lf%lf",&d[i].fa,&d[i].fb,&d[i].R);
		d[i].id=i;	
	    d[i].k=d[i].fa/d[i].fb;
	}
	cdq(1,n);
	ans=d[i].f;
for(i=2;i<=n;i++)
{
	ans=max(ans,d[i].f);
}
printf("%.3lf",ans);
}


       

     


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值