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;
}

浙公网安备 33010602011771号