[BZOJ 1492]货币兑换Cash


维护凸壳


CDQ

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define maxn 100010
using namespace std;

const double eps = 1e-8;

const int inf = 0x7fffffff;

struct opt{
	double q, a, b, rate, k;
	int pos;
}q[maxn], nq[maxn];

int Filter(double x){
	return x > eps ? 1 : (x < -eps ? -1 : 0);
}

struct Point{
	double x, y;
	bool operator<(const Point& k)const{
		return (Filter(x - k.x) < 0) || 
		(Filter(x - k.x) == 0 && Filter(y - k.y) < 0);
	}
}p[maxn], np[maxn];

double f[maxn];
int st[maxn], n, m;
#define K getk
double K(int i, int j){
	if (i == 0) return -inf;
    if (j == 0) return inf;
    if (Filter(p[i].x-p[j].x) == 0) return -inf;
	return (p[i].y - p[j].y) / (p[i].x - p[j].x);
}


void solve(int l, int r){
	if(l == r){
		f[l] = max(f[l - 1], f[l]);
		p[l].x = f[l] / (q[l].a * q[l].rate + q[l].b) * q[l].rate;
		p[l].y = f[l] / (q[l].a * q[l].rate + q[l].b);
		return;
	}
    int mid = l + r >> 1, l1 = l, l2 = mid + 1;
    for(int i = l; i <= r; i ++)
		if(q[i].pos <= mid)nq[l1 ++] = q[i];
		else nq[l2 ++] = q[i];
	memcpy(q + l, nq + l, sizeof (q[0]) * (r - l + 1));
	
    solve(l, mid);
    
	int top = 0;
	
	for(int i = l; i <= mid; i ++){
		while(top >= 2 && Filter(K(i, st[top]) - K(st[top], st[top - 1])) >= 0)
			top --;
		st[++ top] = i;
	}
	
	int j = 1;
	for(int i = r; i >= mid + 1; i --){
		while(j < top && Filter(q[i].k - K(st[j], st[j + 1])) <= 0)
			j ++;
		f[q[i].pos] = max(f[q[i].pos], p[st[j]].x * q[i].a + p[st[j]].y * q[i].b);
	}
	
	solve(mid + 1, r);
	l1 = l, l2 = mid + 1;
	for(int i = l; i <= r; i ++){
		if((p[l1] < p[l2] || l2 > r) && l1 <= mid)
			np[i] = p[l1 ++];
		else np[i] = p[l2 ++];
	}
	memcpy(p + l, np + l, sizeof (p[0]) * (r - l + 1));
}

bool cmp(const opt& a, const opt& b){
	return a.k < b.k;
}

int main(){
	scanf("%d", &n);
	scanf("%lf", &f[0]);
	for(int i = 1; i <= n; i ++){
		scanf("%lf%lf%lf", &q[i].a, &q[i].b, &q[i].rate);
		q[i].k = -q[i].a / q[i].b;
		q[i].pos = i;
	}	
	sort(q + 1, q + 1 + n, cmp);
	solve(1, n);
	printf("%.3lf\n", f[n]);
	return 0;
}


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值