分析:
非常经典的CDQ版题。。。不知道为什么之前没写博客。。现在补上。
首先,不难得到一个会T的DP,定义 DP[i] D P [ i ] 表示前i天能得到的最大钱数。
DP[i]=max{DP[j]∗Ai+DP[j]/ratej∗Bi}
D
P
[
i
]
=
m
a
x
{
D
P
[
j
]
∗
A
i
+
D
P
[
j
]
/
r
a
t
e
j
∗
B
i
}
即表示在第j天把所有钱换成金券,在第i天再全部换成钱。
在贪心的思路下,这个应该还是算显然的。
然后考虑斜率优化,定义
j<k
j
<
k
且
j
j
优于
那么
然而。。我们发现这个式子就非常恶心了。。。 AiBi A i B i 不是单调的!
所以呢,引入CDQ分治来解决。
首先,根据可以先根据 −AiBi − A i B i 排个序。
然后呢,分段处理DP
每一段先按照 i i 归并排序。
然后用单调队列处理右半区间的所有DP值,此时可以保证左侧的升序,所以就用普通的斜率优化的格式就可以处理了。
对了,这题要注意必须先处理左半区间,再处理当前区间的转移,再处理右半区间。因为本题中Dp值需要先左边更新了右边,才能得到右边的位置真正的DP值。(即如果先处理右半区间,再处理当前区间的话,可能会使得处理右侧时的DP值不是最优的)
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<vector>
#include<cmath>
#define SF scanf
#define PF printf
#define MAXN 100010
#define INF 0x3FFFFFFF
#define EPS 1e-9
using namespace std;
int n;
double s;
struct node{
double x,y,a,b,k,rate;
int w,id;
bool operator < (const node &a)const {
return a.k<k;
}
}p[MAXN],t[MAXN];
int st[MAXN],top;
double f[MAXN];
double getk(int a,int b){
if(b==0)
return -INF;
if(fabs(p[a].x-p[b].x)<EPS) return INF;
return (p[b].y-p[a].y)/(p[b].x-p[a].x);
}
void solve(int l,int r){
if(l==r){
f[l]=max(f[l],f[l-1]);
p[l].y=f[l]/(p[l].a*p[l].rate+p[l].b);
p[l].x=p[l].rate*p[l].y;
return ;
}
int l1,l2,mid=(l+r)>>1,j=1;
l1=l;
l2=mid+1;
for(int i=l;i<=r;i++){
if(p[i].id<=mid)
t[l1++]=p[i];
else
t[l2++]=p[i];
}
for(int i=l;i<=r;i++)
p[i]=t[i];
solve(l,mid);
top=0;
for(int i=l;i<=mid;i++){
while(top>1&&getk(st[top-1],st[top])<getk(st[top-1],i)+EPS)
top--;
st[++top]=i;
}
st[++top]=0;
for(int i=mid+1;i<=r;i++){
while(j<top&&getk(st[j],st[j+1])+EPS>p[i].k)
j++;
f[p[i].id]=max(f[p[i].id],p[st[j]].x*p[i].a+p[st[j]].y*p[i].b);
}
solve(mid+1,r);
l1=l;
l2=mid+1;
for(int i=l;i<=r;i++){
if(((p[l1].x<p[l2].x||(fabs(p[l1].x-p[l2].x)<EPS&&p[l1].y<p[l2].y))||l2>r)&&l1<=mid)
t[i]=p[l1++];
else
t[i]=p[l2++];
}
for(int i=l;i<=r;i++)
p[i]=t[i];
}
int main(){
SF("%d%lf",&n,&f[0]);
for(int i=1;i<=n;i++){
SF("%lf%lf%lf",&p[i].a,&p[i].b,&p[i].rate);
p[i].k=-p[i].a/p[i].b;
p[i].id=i;
}
sort(p+1,p+1+n);
//PF("{%.3f %.3f}\n",p[1].k,p[2].k);
solve(1,n);
PF("%.3lf",f[n]);
}