[DP 斜率优化 CDQ分治||动态维护凸包] BZOJ 1492 [NOI2007]货币兑换Cash

23 篇文章 0 订阅
11 篇文章 0 订阅



打了个set维护凸包 cdq等待填坑


#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<iostream>
#include<set>
#include<cmath>
#define dprintf(...) fprintf(stderr,__VA_ARGS__)
using namespace std;
//typedef long double ld;
typedef double ld;

inline void read(ld &x){
	double a; scanf("%lf",&a); x=a;
}

const ld eps=1e-8;
inline int dcmp(ld a,ld b){
	if (fabs(a-b)<eps) return 0;
	return a<b?-1:1;
}

const int N=200005;

inline double sqr(int x){ return (double)x*x; }

struct Point{
    ld x,y;
    Point(ld x=0,ld y=0):x(x),y(y) { }
    void print() const { dprintf("%.3lf %.3lf",x,y); }
    friend bool operator < (Point A,Point B){ return dcmp(A.x,B.x)==0?dcmp(A.y,B.y)<0:dcmp(A.x,B.x)<0; }
    friend ld operator * (Point A,Point B){ return A.x*B.y-A.y*B.x; }
    friend Point operator - (Point A,Point B){ return Point(A.x-B.x,A.y-B.y); }
    friend double dist(Point A,Point B){ return sqrt(sqr(A.x-B.x)+sqr(A.y-B.y)); }
};

struct Line{
	Point p0,p1;
	Line(Point a,Point b){
		p0=a; p1=b;
	}
	bool operator < (const Line &B) const{
		return dcmp((p1-p0)*(B.p1-B.p0),0)<0;
	}
	void print() const{
		p0.print(); dprintf(" "); p1.print(); 
	}
	ld K()const{
		return (p1.y-p0.y)/(p1.x-p0.x);
	}
};

set<Point> Set; 
set<Line> SetL;
typedef set<Point>::iterator ITER;
typedef set<Line>::iterator IT;

int clk;

inline void Ins(Point x){
    ITER r=Set.lower_bound(x),l=r,t;
    l--;
    if(dcmp((*r-*l)*(x-*l),0)<0) return;
    SetL.erase(Line(*l,*r));
	Set.insert(x);
    while (1)
	{
		t=r; r++;
		if(r==Set.end()) break;
		if(dcmp((*r-x)*(*t-x),0)>0) break;
    	SetL.erase(Line(*t,*r));
		Set.erase(t);
	}
	while (1)
	{
        if (l==Set.begin()) break;
		t=l; l--;
		if(dcmp((*t-x)*(*l-x),0)>0) break;
    	SetL.erase(Line(*l,*t));
		Set.erase(t);
	}
    Set.insert(x);
	l=r=Set.find(x);
	l--; r++;
	SetL.insert(Line(*l,x)); 
	SetL.insert(Line(x,*r));
//	for (ITER i=Set.begin();i!=Set.end();i++) i->print(),dprintf("\n"); dprintf("\n"); 
//	for (IT i=SetL.begin();i!=SetL.end();i++) i->print(),dprintf("\n"); dprintf("\n"); 
}

int n,S;
ld A[N],B[N],R[N];
ld f[N];
ld lim;

inline void Add(int i){
	ld x=f[i]/(A[i]*R[i]+B[i]),y=R[i]*x;
	Ins(Point(x,y));
}

int main()
{
	scanf("%d%d",&n,&S);
	for (int i=1;i<=n;i++)
		read(A[i]),read(B[i]),read(R[i]);
	Set.insert(Point(0,0)); 
	Set.insert(Point(1e10,-1e20)); SetL.insert(Line(Point(0,0),Point(1e10,-1e20)));
	f[1]=S; Add(1);
	for (int i=2;i<=n;i++)
	{
		clk=i;
		IT it=SetL.lower_bound( Line(Point(0,0),Point(A[i],-B[i])) );
		Point ret=it->p0;
		f[i]=max(f[i-1],B[i]*ret.x+A[i]*ret.y);
		Add(i);
	}
	printf("%.3lf\n",(double)f[n]);
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值