传送门

首先有一个显然的贪心,每次操作都要做到底,为了最优不会出现只卖一部分或者只买一部分的操作

所以设 $f[i]$ 表示前 $i$ 天得到的最大价值,那么对于每一个 $i$,枚举所有 $j<i$,意思就是第 $j$ 天全部买入,第 $i$ 天全部卖出

显然如果知道 $f[j]$,那么就知道第 $j$  天买入多少

设 $A$ 买了 $X$, $B$ 买了 $Y$,那么 $f[i]=a[i]*X+b[i]*Y$

因为 $X,Y$ 只和 $j$ 有关,显然可以斜率优化

具体就是 $-a[i]*X+f[i]=b[i]*Y$,同除一个 $b[i]$,变成 $-a[i]/b[i]*X+f[i]/b[i]=Y$
那么 $k=-a[i]/b[i],x=X,b=f[i]/b[i],y=Y$

自己推一下,容易得出 $X_i=f[i]*r[i]/(a[i]*r[i]+b[i]),Y_i=f[i]/(a[i]*r[i]+b[i])$

然后因为 $k,x$ 都不单调,所以要用 $CDQ$ 搞

先按斜率排序,然后 $CQD$ 分治之前按下标拆成两部分,这个具体还是看代码吧...

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
typedef long long ll;
typedef double db;
inline int read()
{
int x=,f=; char ch=getchar();
while(ch<''||ch>'') { if(ch=='-') f=-; ch=getchar(); }
while(ch>=''&&ch<='') { x=(x<<)+(x<<)+(ch^); ch=getchar(); }
return x*f;
}
const int N=2e5+,INF=1e9+;
const db eps=1e-;
int n,S;
db f[N];
struct dat{
db k,x,y,a,b,r;
int id;
inline bool operator < (const dat &tmp) const {
return k<tmp.k;
}
}T[N],tmp[N];
inline db slope(int i,int j)//求斜率维护凸包
{
if(fabs(T[i].x-T[j].x)<=eps) return T[i].y>T[j].y ? INF : -INF;
return (T[i].y-T[j].y)/(T[i].x-T[j].x);
}
inline db Cross(db xa,db ya,db xb,db yb) { return xa*yb-xb*ya; }//用叉积维护凸包会更快
inline void merge(int l,int r,int mid)//按x归并排序
{
int pl=l,pr=mid+;
for(int p=l;p<=r;p++)
{
if(pl<=mid&& (pr>r||T[pl].x<T[pr].x/*+eps*/) ) tmp[p]=T[pl++];
else tmp[p]=T[pr++];
}
for(int p=l;p<=r;p++) T[p]=tmp[p];
}
int Q[N];//栈,维护凸包
void CDQ(int l,int r)
{
if(l==r)//到了最底下,此时f[l]已经被所有f[j](j<l)更新完毕
{
f[l]=max(f[l],f[l-]);//这一天可以不操作
T[l].y=f[l]/(T[l].a*T[l].r+T[l].b),T[l].x=T[l].y*T[l].r;
//更新f[l]完才求X[l],Y[l]
return;
}
int mid=l+r>>,pl=l,pr=mid+,top=;
for(int p=l;p<=r;p++)//按下标分开
{
if(T[p].id<=mid) tmp[pl++]=T[p];
else tmp[pr++]=T[p];
}
for(int p=l;p<=r;p++) T[p]=tmp[p];
CDQ(l,mid); Q[]=;//先处理左边
for(int i=l;i<=mid;i++)//此时左边全部更新完毕,可以维护左边构成的凸包了
//注意此时左边的T[i].x是有序的,因为每次CDQ结束都会merge
{
while( top> &&
Cross(T[i].x-T[Q[top-]].x,T[i].y-T[Q[top-]].y,T[Q[top]].x-T[Q[top-]].x,T[Q[top]].y-T[Q[top-]].y)<= ) top--;
Q[++top]=i;
}
for(int i=mid+;i<=r;i++)//用左边构成的凸包更新右边,此时右边的斜率是有序的
{
while( top> && /*T[i].k>=slope(Q[top-1],Q[top])+eps*/ //注释的内容和下一行是等价的,注意eps
Cross(,T[i].k,T[Q[top]].x-T[Q[top-]].x,T[Q[top]].y-T[Q[top-]].y)<= ) top--;
int j=Q[top]; f[T[i].id]=max(f[T[i].id],T[j].x*T[i].a+T[j].y*T[i].b);//更新
}
CDQ(mid+,r); merge(l,r,mid);//处理右边后按x排序
}
int main()
{
n=read(); f[]=read();
for(int i=;i<=n;i++)
{
scanf("%lf%lf%lf",&T[i].a,&T[i].b,&T[i].r);
T[i].k=-T[i].a/T[i].b; T[i].id=i;//初始化
}
sort(T+,T+n+); CDQ(,n);//先按k排序再CDQ
printf("%.3lf",f[n]);
return ;
}

P4027 [NOI2007]货币兑换的更多相关文章

  1. P4027 [NOI2007]货币兑换(斜率优化dp+cdq分治)

    P4027 [NOI2007]货币兑换 显然,如果某一天要买券,一定是把钱全部花掉.否则不是最优(攒着干啥) 我们设$f[j]$为第$j$天时用户手上最多有多少钱 设$w$为花完钱买到的$B$券数 $ ...

  2. 洛谷 P4027 [NOI2007]货币兑换 解题报告

    P4027 [NOI2007]货币兑换 题目描述 小 \(Y\) 最近在一家金券交易所工作.该金券交易所只发行交易两种金券:\(A\) 纪念券(以下简称 \(A\) 券)和 \(B\) 纪念券(以下简 ...

  3. 洛谷P4027 [NOI2007]货币兑换

    P4027 [NOI2007]货币兑换 算法:dp+斜率优化 题面十分冗长,题意大概是有一种金券每天价值会有变化,你可以在某些时间点买入或卖出所有的金券,问最大收益 根据题意,很容易列出朴素的状态转移 ...

  4. LOJ 2353 & 洛谷 P4027 [NOI2007]货币兑换(CDQ 分治维护斜率优化)

    题目传送门 纪念一下第一道(?)自己 yy 出来的 NOI 题. 考虑 dp,\(dp[i]\) 表示到第 \(i\) 天最多有多少钱. 那么有 \(dp[i]=\max\{\max\limits_{ ...

  5. 洛谷P4027 [NOI2007]货币兑换(dp 斜率优化 cdq 二分)

    题意 题目链接 Sol 解题的关键是看到题目里的提示... 设\(f[i]\)表示到第\(i\)天所持有软妹币的最大数量,显然答案为\(max_{i = 1}^n f[i]\) 转移为\(f_i = ...

  6. LUOGU P4027 [NOI2007]货币兑换 (斜率优化+CDQ分治)

    传送门 解题思路 题目里有两句提示一定要看清楚,要不全买要不全卖,所以dp方程就比较好列,f[i]=max(f[j]*rate[j]*a[i])/(rate[j]*a[j]+b[j])+(f[j]*b ...

  7. BZOJ 1492: [NOI2007]货币兑换Cash( dp + 平衡树 )

    dp(i) = max(dp(i-1), x[j]*a[i]+y[j]*b[i]), 0<j<i. x, y表示某天拥有的最多钱去买金券, 金券a和金券b的数量. 然后就很明显了...平衡 ...

  8. bzoj1492[NOI2007]货币兑换Cash cdq分治+斜率优化dp

    1492: [NOI2007]货币兑换Cash Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 5541  Solved: 2228[Submit][Sta ...

  9. cdq分治(hdu 5618 Jam's problem again[陌上花开]、CQOI 2011 动态逆序对、hdu 4742 Pinball Game、hdu 4456 Crowd、[HEOI2016/TJOI2016]序列、[NOI2007]货币兑换 )

    hdu 5618 Jam's problem again #include <bits/stdc++.h> #define MAXN 100010 using namespace std; ...

随机推荐

  1. URAL 1430. Crime and Punishment(数论)

    题目链接 题意 :给你a,b,n,让你找出两个数x,y,使得n-(a*x+b*y)最小. 思路 : 分大小做,然后枚举a的倍数 #include <stdio.h> #include &l ...

  2. servlet及xml文件处理流程

    启动项目----会找到web.xml文件---跳转到默认jsp----页面重定向----转到xml.文件下 通过<servlet-mapping>映射找到<servlet>标签 ...

  3. Python 抓取html所有特定元素的方法

    直接上代码哦,够直接了吧~ from lxml import etree #import mechanize import lxml.html #import cookielib #br = mech ...

  4. Android小技巧

    一.android:clipChildren属性 效果图 看到这个图时你可以先想想如果是你,你怎么实现这个效果.马上想到用RelativeLayout?NO,NO,NO,,, 实现代码 <?xm ...

  5. Linq to Entities基础之需要熟知14个linq关键字(from,where,select,group,let,on,by...)

    1.Linq基础 <1> 关键词: from,in,group,by,where..... MSDN上总结的有14个关键词法... from xxxx in xxxx select =&g ...

  6. log4net 入门使用

    log4net 是dotnet平台下的一个日记记录组件. 一  NuGet中安装log4net包: 二 配置log4net.config文件 配置文件内容: <?xml version=&quo ...

  7. sql server不用安装sql管理工具开启sa

    今天无意间发现腾讯云镜像有windows server2016,追求新系统的我,马上就重装了云服务器.重装完后发现,配置太低,远程桌面都变得不是很顺畅,于是装完sql server2016后便不打算另 ...

  8. C++三种野指针及应对/内存泄露

    C++三种野指针及应对/内存泄露    野指针,也就是指向不可用内存区域的指针.如果对野指针进行操作,将会使程序发生不可预知的错误,甚至可能直接引起崩溃.         野指针不是NULL指针,是指 ...

  9. ML.NET---.NET下的机器学习引擎(简介)

    ML.NET 是一个跨平台的开源机器学习框架,它可以使 .NET 开发人员更容易的开展机器学习工作. ML.NET 允许 .NET 开发人员开发自己的模型,即使没有机器学习的开发经验,也可以很容易的将 ...

  10. Mysql数据类型《二》字符类型

    字符类型 #官网:https://dev.mysql.com/doc/refman/5.7/en/char.html #注意:char和varchar括号内的参数指的都是字符的长度 #char类型:定 ...