ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[NOI2007] 货币兑换

2021-02-23 10:05:09  阅读:246  来源: 互联网

标签:return int double getf NOI2007 兑换 货币 frac ja


前言

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

题目

洛谷

讲解

思路来源: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_i\max\{A_j\frac{a_i}{b_i}+B_j\}\)

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

李超线段树!!!

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

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

其实可以优化一下,因为我们发现本题中我们插入的线段定义域都是 \(x\in[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;}//win easily
		else if(wl <= xl && wr <= xr) return;//lose easily 
		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;
}

标签:return,int,double,getf,NOI2007,兑换,货币,frac,ja
来源: https://www.cnblogs.com/PPLPPL/p/14434310.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有