P4027 [NOI2007]货币兑换
首先有一个显然的贪心,每次操作都要做到底,为了最优不会出现只卖一部分或者只买一部分的操作
所以设 $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]货币兑换的更多相关文章
- P4027 [NOI2007]货币兑换(斜率优化dp+cdq分治)
P4027 [NOI2007]货币兑换 显然,如果某一天要买券,一定是把钱全部花掉.否则不是最优(攒着干啥) 我们设$f[j]$为第$j$天时用户手上最多有多少钱 设$w$为花完钱买到的$B$券数 $ ...
- 洛谷 P4027 [NOI2007]货币兑换 解题报告
P4027 [NOI2007]货币兑换 题目描述 小 \(Y\) 最近在一家金券交易所工作.该金券交易所只发行交易两种金券:\(A\) 纪念券(以下简称 \(A\) 券)和 \(B\) 纪念券(以下简 ...
- 洛谷P4027 [NOI2007]货币兑换
P4027 [NOI2007]货币兑换 算法:dp+斜率优化 题面十分冗长,题意大概是有一种金券每天价值会有变化,你可以在某些时间点买入或卖出所有的金券,问最大收益 根据题意,很容易列出朴素的状态转移 ...
- LOJ 2353 & 洛谷 P4027 [NOI2007]货币兑换(CDQ 分治维护斜率优化)
题目传送门 纪念一下第一道(?)自己 yy 出来的 NOI 题. 考虑 dp,\(dp[i]\) 表示到第 \(i\) 天最多有多少钱. 那么有 \(dp[i]=\max\{\max\limits_{ ...
- 洛谷P4027 [NOI2007]货币兑换(dp 斜率优化 cdq 二分)
题意 题目链接 Sol 解题的关键是看到题目里的提示... 设\(f[i]\)表示到第\(i\)天所持有软妹币的最大数量,显然答案为\(max_{i = 1}^n f[i]\) 转移为\(f_i = ...
- LUOGU P4027 [NOI2007]货币兑换 (斜率优化+CDQ分治)
传送门 解题思路 题目里有两句提示一定要看清楚,要不全买要不全卖,所以dp方程就比较好列,f[i]=max(f[j]*rate[j]*a[i])/(rate[j]*a[j]+b[j])+(f[j]*b ...
- 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的数量. 然后就很明显了...平衡 ...
- bzoj1492[NOI2007]货币兑换Cash cdq分治+斜率优化dp
1492: [NOI2007]货币兑换Cash Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 5541 Solved: 2228[Submit][Sta ...
- 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; ...
随机推荐
- CentOS-yum基本使用
CentOS: yum URL: ftp://172.16.0.1/pub/ YUM: yellow dog, Yellowdog Update Modifier yum repository: yu ...
- Part3_lesson2---ARM指令分类学习
1.算术和逻辑指令 mov.mvn.cmp.tst.sub.add.and.bic 2.比较指令 cmp和tst 3.跳转指令 b和bl 4.移位指令 lsl和ror 5.程序状态字访问指令 msr与 ...
- Spring框架总结(十一)
切入点表达式 可以对指定的“方法”进行拦截:从而给指定的方法所在的类生层代理对象. 其他跟十一样,只更改bean.xml <?xml version="1.0" encodi ...
- CodeForces 288A Polo the Penguin and Strings (水题)
题意:给定一个字符,让你用前 k 个字符把它排成 n 长度,相邻的字符不能相等,并且把字典序最小. 析:其实很简单么,我们只要多循环ab,就行,最后再把剩下的放上,要注意k为1的时候. 代码如下: # ...
- .NET基础 (07)异常的处理
异常的处理1 如何针对不同的异常进行捕捉2 如何使用Conditional特性3 如何避免类型转换时的异常 异常的处理 1 如何针对不同的异常进行捕捉 C#中一个try块可以有多个catch块,每个c ...
- 常用的String方法Math方法
Arrays.sort();冒泡排序字符串.charAt(i);字符串索引i上的字符Integer.prsent(字符串) 字符串转整数equals(Object anObject) 将此字符串与指定 ...
- SOAP协议初级指南 (一)
SOAP(Simple Object Access Protocal) 技术有助于实现大量异构程序和平台之间的互操作性,从而使存在的应用能够被广泛的用户所访问.SOAP是把成熟的基于HTTP的WEB技 ...
- Android R文件的id
如果你用 apktoool 反编译过 apk 就知道,反编译后res/values 下有一个 public.xml 文件,内容如图 这个东西有什么用呢? 先从如何使用资源 ID 开始,在开 ...
- Nutch2.x 集成ElasticSearch 抓取+索引
http://blog.csdn.net/eryk86/article/details/14111811 使用https://github.com/apache/nutch.git导入nutch项 ...
- Asp.Net Core下的两种路由配置方式
与Asp.Net Mvc创建区域的时候会自动为你创建区域路由方式不同的是,Asp.Net Core下需要自己手动做一些配置,但更灵活了. 我们先创建一个区域,如下图 然后我们启动访问/Manage/H ...