luogu P4027
loj 2353

Description

某人在炒股,有A,B两种股票,第\(i\)天买卖一单位A、B股需\(a_i\),\(b_i\)元。每天可以多次操作,每次可以卖出手里op%的A和B股,或者买进数量\(rate_i:1\)的A、B两种股票。问第\(n\)天手里最多的股票。

Solution

1.题面末端给了提示:要么用光手里的钱买,要么卖完手里所有的股票
2.对于多次操作,因为每天无论买卖交易同一种股票都是一个价钱,不会对该天股票又买又卖。因此顶多会出现先卖(一开始手里有的)后买,然后该天结束。
这样op=100,且知道当时手里的钱\(f\)是可以利用比例\(1:rate_i\)推出分别可以卖的A、B股票数。
这样每天三种决策(不动/买/卖),\(f\)维护当天手里最多的钱。
不动:\(f_i=max(f_{i-1},f_i)\)
发现买可以由\(f\)推出。因此只用考虑卖。
卖:决策前面买入股票的那天\(j\)。懒得写柿子了具体见:luogu题解
总之式子可以推出\(x\)关于\(i\)的,斜率和截距跟\(j\)有关的直线。
用超哥线段树。不然还要写cdq/平衡树优化+斜率优化,嘿嘿……

easy code

戳我
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
const int N=1e6+5;
int id,bst[N];
db c[N],d[N],k[N],b[N],A[N],B[N],C[N];
db F(int p,int x) {return c[x]*k[p]+b[p];}
void Update(int x,int l,int r) {
	if(l==r) {
		if(F(bst[x],l)<F(id,l)) bst[x]=id;
		return;
	}
	int mid=(l+r)>>1;
	if(F(bst[x],mid)<F(id,mid)) swap(bst[x],id);
	if(F(bst[x],l)<F(id,l))Update(x<<1,l,mid);
	else if(F(bst[x],r)<F(id,r))Update(x<<1|1,mid+1,r);
}
int X;
db Query(int x,int l,int r) {
	if(l==r) return bst[x]?F(bst[x],X):0;
	int mid=(l+r)>>1;
	return max(!bst[x]?0.0:F(bst[x],X),(X<=mid?Query(x<<1,l,mid):Query(x<<1|1,mid+1,r)));
}
int main() {
	int n;db f,g;
	scanf("%d%lf",&n,&f);
	for(int i=1;i<=n;i++) {
		scanf("%lf%lf%lf",&A[i],&B[i],&C[i]);
		c[i]=d[i]=1.0*A[i]/B[i];
	}
	sort(c+1,c+1+n);
	for(int i=1;i<=n;i++) {
		id=i;
		X=lower_bound(c+1,c+1+n,d[i])-c;f=max(f,B[i]*Query(1,1,n));
		g=A[i]*C[i]+B[i];b[i]=f/g;k[i]=b[i]*C[i];Update(1,1,n);
	}
	printf("%.3lf",f);
	return 0;
}