P4027 [NOI2007] 货币兑换

\(f_i\) 表示第 \(i\) 天最大的收益。

初始条件 \(f_0=s\),答案 \(f_n\)

转移枚举上一个全买券的点 \(j\),设 \(y\) 表示第 \(j\) 天买 \(B\) 的数量,解方程。

\(Rate_j\times y_j\times a_j+y_j\times b_j=f_j\)

得到 \(y_j=\large\frac{f_j}{Rate_j\times a_j+b_j}\)

\(x\) 表示买 \(A\) 的数量,显然 \(x_i=Rate_j\times y_i\)

转移方程 \(f_i=\max(f_{i-1},\max\{a_i\times x_j+b_i\times y_j | j\in[1,i) \} )\)

提出 \(b_i\),得到 \(f_i=\max(f_{i-1},b_i\times \max\{\large\frac{a_i}{b_i}\small\times x_j+y_j\})\)

发现变成一次函数形式,即对于每个 \(x_j,y_j\),查询 \(\large\frac{a_i}{b_i}\) 处的最大值即可。

李超线段树。

缺省源太丑,只放核心代码了 qwq。

db val(int i,int t){return x[t]*k[i]+y[t];}
void modify(int p,int id,int l,int r){
	if(l==r){
		if(val(l,id)>val(l,t[p])) t[p]=id;
		return;
	}
	int mid=(l+r)>>1;
	if(val(mid,id)>val(mid,t[p])) swap(id,t[p]);
	if(val(l,id)>val(l,t[p])) modify(ls,id,l,mid);
	else modify(rs,id,mid+1,r);
}
db query(int p,int l,int r){
	if(l==r) return val(now,t[p]);
	int mid=(l+r)>>1;
	if(now<=mid) return Max(val(now,t[p]),query(ls,l,mid));
	return Max(val(now,t[p]),query(rs,mid+1,r));
}
int main(){IOS;
	int n,s;
	cin>>n>>s;
	f[0]=s;
	F(i,1,n) cin>>a[i]>>b[i]>>r[i],k[i]=a[i]/b[i],kk[i]=k[i];
	sort(k+1,k+1+n);
	F(i,1,n){
		now=lower_bound(k+1,k+n+1,kk[i])-k;
		f[i]=max(f[i-1],b[i]*query(1,1,n));
		db tmp=a[i]*r[i]+b[i];
		y[i]=f[i]/tmp;
		x[i]=r[i]*y[i];
		modify(1,i,1,n);
	}
	cout<<fixed<<setprecision(3)<<f[n]<<endl;
	return 0;
}
posted @ 2024-03-25 10:34  Mr_KaYa  阅读(7)  评论(0)    收藏  举报