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

    前言

    妙啊,我最喜欢码农题偷懒了。

    题目

    洛谷

    讲解

    思路来源:panyf orz

    首先 (O(n^2))(dp) 很好想,令 (f_i) 为第 (i) 天最多获得的钱,则有:

    (f_i=max{frac{f_j*Rate_ja_i}{Rate_ja_j+b_j}+frac{f_j*b_i}{Rate_ja_j+b_j}})

    (A_j=frac{f_j*Rate_j}{Rate_ja_j+b_j},B_j=frac{f_j}{Rate_ja_j+b_j})

    (f_i=max{A_ja_i+B_jb_i}=b_imax{A_jfrac{a_i}{b_i}+B_j})

    哦,后面的 (A_jfrac{a_i}{b_i}+B_j) 不就是一次函数 (kx+b) 的形式吗?!

    李超线段树!!!

    为防止精度误差,要对 (frac{a_i}{b_i}) 离散化,而且这样常数也会小一些,不需要浮点数动态开点。

    时间复杂度 (O(nlog^2n))

    其实可以优化一下,因为我们发现本题中我们插入的线段定义域都是 (xin[1,n])(离散化后),所以我们在插入的时候一定不会走两边,可以少掉一个 (log)

    还有一个(color{white}{小})优化是在询问时如果一个区间中没有线段,那么下面一定也没有,直接返回,与上一个优化同理。

    Query没返回值还能过40pts是我没想到的。

    代码

    const int MAXN = 100005;
    int n;
    double S,a[MAXN],b[MAXN],r[MAXN],lsh[MAXN];
    
    struct line
    {
    	double k,b;
    	bool f;//whether it exist or not
    	line(){} 
    	line(double k1,double b1,bool f1){
    		k = k1;
    		b = b1;
    		f = f1;
    	} 
    };
    double getf(line l,int x){return l.k * lsh[x] + l.b;}
    
    #define lc (x<<1)
    #define rc (x<<1|1)
    struct LiChaoSegmentTree
    {
    	line t[MAXN << 2];
    	void Add_Line(int x,int l,int r,line w) 
    	{
    		int mid = (l+r) >> 1;
    		if(!t[x].f) {t[x] = w;return;}
    		double xl = getf(t[x],l),xr = getf(t[x],r),wl = getf(w,l),wr = getf(w,r);
    		if(wl >= xl && wr >= xr) {swap(t[x],w);return;}//completely win
    		else if(wl <= xl && wr <= xr) return;//completely lose 
    		else//worthy opponent
    		{
    			if(getf(w,mid) >= getf(t[x],mid)) swap(t[x],w);
    			//if(l == r) return ; boundary (It's unnecessary.)
    			if(getf(w,l) > getf(t[x],l)) Add_Line(lc,l,mid,w);
    			else Add_Line(rc,mid+1,r,w);
    			return ;
    		}
    	}
    	
    	double Query(int x,int l,int r,int pos)
    	{
    		if(!t[x].f) return 0;//Especially suitable for this subject,for its segments all exist in [1,n].
    		double ret = getf(t[x],pos);
    		if(l == r) return ret;
    		int mid = (l+r) >> 1;
    		if(pos <= mid) ret = Max(ret,Query(lc,l,mid,pos));
    		else ret = Max(ret,Query(rc,mid+1,r,pos));
    		return ret;
    	}
    }st;
    
    int main()
    {
    //	freopen(".in","r",stdin);
    //      freopen(".out","w",stdout);
    	scanf("%d %lf",&n,&S);
    	for(int i = 1;i <= n;++ i)
    	{
    		scanf("%lf %lf %lf",&a[i],&b[i],&r[i]);
    		lsh[i] = a[i] / b[i];
    	}
    	sort(lsh+1,lsh+n+1);
    	for(int i = 1;i <= n;++ i)
    	{
    		int x = lower_bound(lsh+1,lsh+n+1,a[i]/b[i]) - lsh;
    		S = Max(S,b[i] * st.Query(1,1,n,x));
    		double K = S * r[i] / (r[i] * a[i] + b[i]),B = S / (r[i] * a[i] + b[i]);
    		st.Add_Line(1,1,n,line(K,B,1));
    	}
    	printf("%.3f",S);
    	return 0;
    }
    
  • 相关阅读:
    RabbitMq安装笔记
    SpringBoot笔记--Jackson
    SpringBoot笔记--FastJson
    由一个“两次请求”引出的Web服务器跨域请求访问问题的解决方案
    转:SpringMVC之类型转换Converter(GenericConverter)
    npm 命令
    数据分页技巧
    Mongo 开发笔记
    Android 开发
    Bash 笔记
  • 原文地址:https://www.cnblogs.com/PPLPPL/p/14434310.html
Copyright © 2011-2022 走看看