[NOI2007]货币兑换

传送门

看完题面,我们可以得出一个结论,我们的操作要么是用完当前所有的钱买入,要么是卖出当前所有的金劵,显然易得。

下面就开始推式子

\[f_n=\max(f_{n-1},\max_{i=1}^{n-1}(\frac{f_ir_i}{r_ia_i+b_i}a_n+\frac{f_i}{r_ia_i+b_i}b_n))\\ set\ g_i=\frac{f_i}{r_ia_i+b_i}\\ f_n=\max(f_{n-1},\max_{i=1}^{n-1}(g_i(r_ia_n+b_n)))\\ g_j(r_ja_n+b_n)<g_k(r_ka_n+b_n)\\ (g_jr_j-g_kr_k)a_n<b_n(g_k-g_j)\\ {g_jr_j-g_kr_k \over g_j-g_k}>-\frac{b_n}{a_n} \]

这里成了斜率优化的经典式子,但是我们阔以发现\(g\)并不一定递增,于是我们考虑以下\(2\)种方法

1.CDQ分治

就像 分治FFT 那样,我们想要得到\([l,r]\)中的\(f\),则先处理\([l,mid]\),再计算\([l,mid]\)\([mid+1,r]\)的贡献,最后计算\([mid+1,r]\)内部的贡献

2.Splay维护动态凸包

这个就没什么多说的必要,敲就完了!(逃

\(\mathfrak{Talk\ is\ cheap,show\ you\ the\ code}.\)

CDQ版

#include<bits/stdc++.h>
using namespace std;
# define ll long long
# define read read1<ll>()
# define Type template<typename T>
Type T read1(){
	T t=0;char k;bool vis=0;
	do (k=getchar())=='-'&&(vis=1);while('0'>k||k>'9');
	while('0'<=k&&k<='9')t=(t<<3)+(t<<1)+(k^'0'),k=getchar();
	return vis?-t:t;
}
# define fre(k) freopen(k".in","r",stdin);freopen(k".out","w",stdout)
int s,id[100005],sta[100005];
double f[100005],r[100005],a[100005],b[100005],g[100005];
map<double,int>ma;
double slope(int x,int y){return (g[x]*r[x]-g[y]*r[y])/(g[x]-g[y]);}
bool judge(int x,int y,int z){return (g[x]*r[x]-g[y]*r[y])*(g[y]-g[z])<=(g[y]*r[y]-g[z]*r[z])*(g[x]-g[y]);}
bool cmp(int x,int y){return g[x]<g[y];}
void solve(int lx,int rx){
	if(lx==rx){
		if(lx!=1)f[lx]=max(f[lx],f[lx-1]);
		g[lx]=f[lx]/(r[lx]*a[lx]+b[lx]);
		return;
	}
	int mid=lx+rx>>1;
	solve(lx,mid);
	sort(id+lx,id+mid+1,cmp);
	ma.clear();
	sta[sta[0]=1]=id[lx];
	for(int i=lx+1;i<=mid;++i){
		while(sta[0]>1&&judge(sta[sta[0]-1],sta[sta[0]],id[i]))--sta[0];
		sta[++sta[0]]=id[i];
	}
	for(int i=1;i<sta[0];++i)
		ma[slope(sta[i+1],sta[i])]=sta[i+1];
	for(int i=mid+1;i<=rx;++i){
		auto y=ma.lower_bound(-b[i]/a[i]);
		int x;
		if(y==ma.end())x=sta[1];
		else x=y->second;
		f[i]=max(f[i],g[x]*(r[x]*a[i]+b[i]));
	}solve(mid+1,rx);
}
int main(){
	s=read;scanf("%lf",f+1);
	for(int i=1;i<=s;id[i]=i,++i)
		scanf("%lf %lf %lf",a+i,b+i,r+i);
	solve(1,s);
	printf("%.3f",f[s]);
	return 0;
}


Splay版

咕咕咕
posted @ 2021-02-23 09:33  ファイナル  阅读(57)  评论(0)    收藏  举报