zoukankan      html  css  js  c++  java
  • BZOJ1492: [NOI2007]货币兑换Cash

    设$x_j$,$y_j$为第$j$天能买的A,B券数量,$f_i$为第$i$天的最大收益。$f_i=max_{1le j<i}a_ix_j+b_iy_j$,最大化$f_i$即找一个点$(x_j,y_j)$,使得这个点和斜率$-a_i/b_i$所确定的直线截距最大。平衡树维护凸包即可,按$x$建平衡树,并维护斜率单调递减,判断删点时用叉积比较优越。比一般的CDQ还快,可能是因为凸包的点数不多,所以平衡树的log就比较小。另外就是不加eps理论上也没有问题。

    #include<cstdio>
    #include<cstdlib>
    typedef double real;
    const int N=1e5+5;
    typedef struct node*ptr;
    struct node{
    	ptr i,j,s,t;real w,x,y;
    	node(){w=rand();}
    }*b,e[N];
    void zag(ptr&x){ptr y=x->j;x->j=y->i,y->i=x,x=y;}
    void zig(ptr&x){ptr y=x->i;x->i=y->j,y->j=x,x=y;}
    void ins(ptr y,ptr&x=b){
    	if(!x)x=y,x->s?x->s->t=x:0,x->t?x->t->s=x:0;
    	else if(y->x>x->x)
    		{ins(y,x->j);if(x->j->w>x->w)zag(x);}
    	else
    		{ins(y,x->i);if(x->i->w>x->w)zig(x);}
    }
    void del(ptr y,ptr&x=b){
    	if(y->x>x->x)del(y,x->j);
    	else if(x->x>y->x)del(y,x->i);
    	else if(!x->i)x=x->j;
    	else if(!x->j)x=x->i;
    	else if(x->i->w>x->j->w)zig(x),del(y,x->j);
    	else zag(x),del(y,x->i);
    }
    ptr pre(real k,ptr x=b){
    	ptr y=0;
    	while(x)k>=x->x?y=x,x=x->j:x=x->i;
    	return y;
    }
    ptr suc(real k,ptr x=b){
    	ptr y=0;
    	while(x)x->x>=k?y=x,x=x->i:x=x->j;
    	return y;
    }
    real slo(ptr s,ptr t){return(s->y-t->y)/(s->x-t->x);}
    real cal(ptr x,ptr s,ptr t){
    	real x1=x->x-s->x,x2=t->x-s->x;
    	real y1=x->y-s->y,y2=t->y-s->y;
    	return x1*y2-x2*y1;
    }
    void upd(ptr x){
    	if(ptr&y=x->s=pre(x->x))
    		while(y->s&&cal(x,y->s,y)<=0)
    			del(y),y=pre(x->x);
    	if(ptr&y=x->t=suc(x->x))
    		while(y->t&&cal(x,y,y->t)<=0)
    			del(y),y=suc(x->x);
    	if(!x->s||!x->t||cal(x->t,x->s,x)>0)
    		ins(x);
    }
    void eq2(real&x,real y){x=x<y?y:x;}
    real s,t,r,f;
    void sol(real k,ptr x=b){
    	if(x->s&&k>slo(x->s,x))sol(k,x->i);
    	else if(x->t&&slo(x,x->t)>k)sol(k,x->j);
    	else eq2(f,s*x->x+t*x->y);
    }
    int main(){
    	int n;
    	scanf("%d%lf",&n,&f);
    	for(int i=1;i<=n;++i){
    		scanf("%lf%lf%lf",&s,&t,&r);
    		if(i>1)sol(-s/t);
    		e[i].x=r*(e[i].y=f/(r*s+t));
    		upd(e+i);
    	}
    	printf("%.3f
    ",f);
    }
    
  • 相关阅读:
    为什么使用GitHub
    java学习笔记
    mysql 内置功能 存储过程 创建有参存储过程
    mysql 字符串类型 char varchar
    前端 HTML 注释
    mysql 内置功能 存储过程 删除存储过程
    前端开发 目录
    mysql 内置功能 存储过程 创建无参存储过程
    mysql 内置功能 存储过程 目录
    mysql 内置功能 存储过程介绍
  • 原文地址:https://www.cnblogs.com/f321dd/p/6113317.html
Copyright © 2011-2022 走看看