zoukankan      html  css  js  c++  java
  • luogu P4027 [NOI2007]货币兑换

    luogu

    ws**

    这里设(f_i)为前(i)天内得到的最多钱数,转移就考虑在第(i)天把钱变成券,然后枚举(>i)(j),在第(j)天换成钱,这里要算出第(i)天换的B券数量,直接写转移(f_j=max(f_{j-1},max_{i<j} frac{f_i}{a_ir_i+b_i}(a_jr_i+b_j)))

    考虑(frac{f_i}{a_ir_i+b_i}(a_jr_i+b_j) o f_j),先改成(frac{f_ir_i}{a_ir_i+b_i}*a_j+frac{f_i}{a_ir_i+b_i}*b_j o f_j),然后设(x_i=frac{f_ir_i}{a_ir_i+b_i},y_i=frac{f_i}{a_ir_i+b_i}),原式改写成(x_ia_j+y_ib_j o f_j)

    然后把(y_i)提出,得(y_i=-frac{a_j}{b_j}x_i+frac{1}{b_j}f_j),所以(f_j)可以看做是对于点((x_i,y_i)),用斜率(k=-frac{a_j}{b_j})去经过这个点,得到的最大的截距的(/b_i)的值.所以如果把前面的所有((x_i,y_i))的上凸壳搞出来,那截距最大的((x_i,y_i))会满足在它前面的点之间的线段斜率(>-frac{a_j}{b_j}),后面的线段斜率(le-frac{a_j}{b_j})(可以画图理解),那么维护好凸壳后就可以每次(O(logn))转移了.由于凸壳一定是由一些横坐标不相同的点依次排列形成,所以可以搞一个以横坐标为关键字的平衡树,每次把新的点插到对应位置,然后用叉积删掉这个点的不合法前驱后继,使得凸包没有凹下去的地方

    不想写平衡树可以写multiset,就是查询大概要两个log

    #include<bits/stdc++.h>
    #define LL long long
    #define db double
    
    using namespace std;
    const int N=1e5+10;
    const db eps=1e-10;
    int rd()
    {
        int x=0,w=1;char ch=0;
        while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+(ch^48);ch=getchar();}
        return x*w;
    }
    db f[N];
    struct node
    {
    	db x,y;
    	bool operator < (const node &bb) const {return x<bb.x;}
    	node operator - (const node &bb) const {return (node){x-bb.x,y-bb.y};}
    	db operator * (const node &bb) const {return x*bb.y-bb.x*y;}
    }nw;
    db K(node aa,node bb){return (bb.y-aa.y)/(bb.x-aa.x);}
    multiset<node> sb;
    multiset<node>::iterator it,nt,n2;
    int n;
    
    int main()
    {
        ///
    	n=rd(),f[1]=rd();
    	for(int i=1;i<=n;++i)
    	{
    		db a,b,c;
    		scanf("%lf%lf%lf",&a,&b,&c);
    		f[i]=max(f[i],f[i-1]);
    		if(!sb.empty())
    		{
    			it=sb.begin(),f[i]=max(f[i],((*it).y+(*it).x*a/b)*b);
    			it=--sb.end(),f[i]=max(f[i],((*it).y+(*it).x*a/b)*b);
    			db l=(*sb.begin()).x+eps,r=(*(--sb.end())).x-eps,ls=1e9;
    			while(r-l>eps&&r-l<ls)
    			{
    				ls=r-l;
    				db md=(l+r)/2;
    				it=sb.upper_bound((node){md,0});
    				if(it==sb.end()) break;
    				nt=--it,++it;
    				f[i]=max(f[i],max((*it).y+(*it).x*a/b,(*nt).y+(*nt).x*a/b)*b);
    				if(K(*it,*nt)>-a/b) l=(*it).x+eps;
    				else r=(*nt).x-eps;
    			}
    		}
    		nw=(node){f[i]/(a*c+b)*c,f[i]/(a*c+b)};
    		it=sb.insert(nw);
    		if(it!=sb.begin()&&it!=(--sb.end()))
    		{
    			nt=n2=it,--nt,++n2;
    			if(((*it)-(*nt))*((*n2)-(*it))>eps){sb.erase(it);continue;}
    		}
    		if(it!=sb.begin())
    		{
    			nt=it,--nt;
    			if(fabs((*it).x-(*nt).x)<eps)
    			{
    				if((*it).y<(*nt).y){sb.erase(it);continue;}
    				sb.erase(nt);
    			}
    		}
    		if(it!=(--sb.end()))
    		{
    			n2=it,++n2;
    			if(fabs((*it).x-(*n2).x)<eps)
    			{
    				if((*it).y<(*n2).y){sb.erase(it);continue;}
    				sb.erase(n2);
    			}
    		}
    		while(it!=sb.begin()&&it!=(++sb.begin()))
    		{
    			nt=it,--nt;
    			n2=nt,--n2;
    			if(((*nt)-(*it))*((*n2)-(*nt))>eps) break;
    			sb.erase(nt);
    		}
    		while(it!=(--sb.end())&&it!=(--(--sb.end())))
    		{
    			nt=it,++nt;
    			n2=nt,++n2;
    			if(((*nt)-(*it))*((*n2)-(*nt))<-eps) break;
    			sb.erase(nt);
    		}
    	}
    	printf("%.3lf
    ",f[n]);
    	return 0;
    }
    
  • 相关阅读:
    [MacOS]Sublime text3 安装(一)
    [RHEL8]开启BBR
    PAT Advanced 1136 A Delayed Palindrome (20分)
    PAT Advanced 1144 The Missing Number (20分)
    PAT Advanced 1041 Be Unique (20分)
    PAT Advanced 1025 PAT Ranking (25分)
    PAT Advanced 1022 Digital Library (30分)
    PAT Advanced 1019 General Palindromic Number (20分)
    PAT Advanced 1011 World Cup Betting (20分)
    PAT Advanced 1102 Invert a Binary Tree (25分)
  • 原文地址:https://www.cnblogs.com/smyjr/p/12722456.html
Copyright © 2011-2022 走看看