bzoj 1492: [NOI2007]货币兑换Cash
Description


Input
Output
只有一个实数MaxProfit,表示第N天的操作结束时能够获得的最大的金钱数目。答案保留3位小数。
Sample Input
1 1 1
1 2 2
2 2 3
Sample Output
HINT

Source
这其实是一道大火题,是CDQ分治的发明题 Orz,Orz,Orz
蒟蒻如我连一个单调都做不出,而这个题就真的实在玩蛇皮了
题目提示解题法:
numa=numb*rk;
numb*(rk*ak+bk)=f[k];
numb=f[k]/(rk*ak+bk);
// MADE BY QT666
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<queue>
#include<set>
#include<cstdlib>
#include<cstring>
#include<string>
#include<ctime>
#define lson num<<1
#define rson num<<1|1
using namespace std;
typedef long long ll;
const int N=100050;
double f[N],a[N],b[N],ak[N],bk[N],rk[N],S;
int n;
int main(){
scanf("%d",&n);scanf("%lf",&S);
for(int i=1;i<=n;i++){
scanf("%lf%lf%lf",&ak[i],&bk[i],&rk[i]);
}
f[0]=S;
for(int i=1;i<=n;i++){
f[i]=f[i-1];
for(int j=1;j<i;j++){
b[j]=f[j]/(rk[j]*ak[j]+bk[j]);a[j]=b[j]*rk[j];
f[i]=max(f[i],a[j]*ak[i]+b[j]*bk[i]);
}
}
printf("%.3f",f[n]);
}
这是我用线打斜率优化的第一道题,关于线的斜率优化表示法见我的斜率优化总结
这一题的方程:
a[j]*ak[i]+b[j]*bk[i]
同时提出一个ak[i]变为:
(a[j]+b[j]*(bk[i]/ak[i]))*ak[i];运用线的套路
令b=a[j],b[j]=k,x=(bk[i]/ak[i]),ak为乘在外面的一个常数
我们发现斜率不是单调的,横坐标也不是单调的,这就不同于普通的都满足单调性的斜率优化
我们考虑普通的斜率优化
需要依赖于斜率的单调性来用单调队列进行队尾的更新来实现O(n)的维护半平面交
需要依赖于横坐标的单调性来用单调队列进行队头决策的移动来实现O(n)的决策转移
然而我们发现这两个步骤都需要依赖于有序,所以CDQ就可以通过离线化无序为有序
我们考虑到转移相当于是一个偏序问题,首先必须满足序号小的向序号大的转移
考虑到CDQ分治的基本思路,用左边的答案来更新右边的答案
我们可以相当于把问题转化为左右两个部分的偏序问题
我们要用左边来更新右边,我们相当于需要在左边斜率递增(斜率单调这个用归并即可以实现)才可以用单调队列实现O(n)维护一个决策的半平面交
然后我们需要在右边横坐标递增,利用左边的决策的半平面交再利用单调队列实现O(n)的决策转移(横坐标单调这个在外面sort一遍即可)
这样相当于两边都是一个二维的偏序问题,至此问题已经被完美解决了,整个分治的流程十分完美
时间复杂度:nlogn
代码:
// MADE BY QT666
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<queue>
#include<set>
#include<cstdlib>
#include<cstring>
#include<string>
#include<ctime>
#define lson num<<1
#define rson num<<1|1
#define eps 1e-9
using namespace std;
typedef long long ll;
const int N=100050;
int cnt;
struct data{double k,x,b;int id;}g[N],p[N],q[N];
double f[N],ak[N],bk[N],rk[N];
bool cmp(const data &a,const data &b){
return a.x<b.x;
}
void solve(int l,int r){
if(l==r) return;
int mid=(l+r)>>1,l1=l,l2=mid+1,head=1,tail=0;
double MAX=0;
for(int i=l;i<=r;i++){
cnt++;
if(g[i].id<=mid) p[l1++]=g[i];
else p[l2++]=g[i];
}
for(int i=l;i<=r;i++) g[i]=p[i];
solve(l,mid);
for(int i=l;i<=mid;i++){
while(head<tail&&(g[i].k-q[tail].k)*(q[tail-1].b-q[tail].b)>=(q[tail].k-q[tail-1].k)*(q[tail].b-g[i].b))
tail--;
q[++tail]=g[i],MAX=max(MAX,f[g[i].id]);
}
sort(g+mid+1,g+r+1,cmp);
for(int i=mid+1;i<=r;i++){
while(head<tail&&q[head].k*g[i].x+q[head].b<=q[head+1].k*g[i].x+q[head+1].b)
head++;
f[g[i].id]=max(f[g[i].id],max(MAX,ak[g[i].id]*(q[head].k*g[i].x+q[head].b)));
g[i].k=f[g[i].id]/(ak[g[i].id]*rk[g[i].id]+bk[g[i].id]),g[i].b=g[i].k*rk[g[i].id];
}
solve(mid+1,r);l1=l,l2=mid+1;
for(int i=l;i<=r;i++){
if(l2>r||(l1<=mid&&g[l1].k<=g[l2].k)) p[i]=g[l1++];
else p[i]=g[l2++];
}
for(int i=l;i<=r;i++) g[i]=p[i];
}
int main()
{
int n;
cin>>n;scanf("%lf",&f[0]);
for(int i=1;i<=n;i++){
scanf("%lf%lf%lf",&ak[i],&bk[i],&rk[i]);
f[i]=f[0];
g[i].id=i,g[i].x=bk[i]/ak[i],g[i].k=f[i]/(rk[i]*ak[i]+bk[i]),g[i].b=g[i].k*rk[i];
}
solve(1,n);
printf("%.3f",f[n]);
}
bzoj 1492: [NOI2007]货币兑换Cash的更多相关文章
- 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的数量. 然后就很明显了...平衡 ...
- ●BZOJ 1492 [NOI2007]货币兑换Cash
题链: http://www.lydsy.com/JudgeOnline/problem.php?id=1492 题解: 斜率优化DP,CDQ分治 定义$DP[i]$为第i天结束后的最大收益. 由于题 ...
- bzoj 1492 [NOI2007]货币兑换Cash(斜率dp+cdq分治)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1492 [题意] 有AB两种货币,每天可以可以付IPi元,买到A券和B券,且A:B= ...
- 斜率优化(CDQ分治,Splay平衡树):BZOJ 1492: [NOI2007]货币兑换Cash
Description Input 第一行两个正整数N.S,分别表示小Y 能预知的天数以及初始时拥有的钱数. 接下来N 行,第K 行三个实数AK.BK.RateK,意义如题目中所述 Output 只有 ...
- BZOJ 1492: [NOI2007]货币兑换Cash [CDQ分治 斜率优化DP]
传送门 题意:不想写... 扔链接就跑 好吧我回来了 首先发现每次兑换一定是全部兑换,因为你兑换说明有利可图,是为了后面的某一天两种卷的汇率差别明显而兑换 那么一定拿全利啊,一定比多天的组合好 $f[ ...
- BZOJ 1492 [NOI2007]货币兑换Cash:斜率优化dp + cdq分治
传送门 题意 初始时你有 $ s $ 元,接下来有 $ n $ 天. 在第 $ i $ 天,A券的价值为 $ A[i] $ ,B券的价值为 $ B[i] $ . 在第 $ i $ 天,你可以进行两种操 ...
- bzoj 1492: [NOI2007]货币兑换Cash【贪心+斜率优化dp+cdq】
参考:http://www.cnblogs.com/lidaxin/p/5240220.html 虽然splay会方便很多,但是懒得写,于是写了cdq 首先要想到贪心的思路,因为如果在某天买入是能得到 ...
- BZOJ 1492 [NOI2007]货币兑换Cash (CDQ分治/splay 维护凸包)
题目大意:太长了略 splay调了两天一直WA弃疗了 首先,我们可以猜一个贪心,如果买/卖,就一定都买/卖掉,否则不买/卖 反正货币的行情都是已知的,没有任何风险,所以肯定要选择最最最优的方案了 容易 ...
- BZOJ 1492: [NOI2007]货币兑换Cash 斜率优化 + splay动态维护凸包
Description 小Y最近在一家金券交易所工作.该金券交易所只发行交易两种金券:A纪念券(以下简称A券)和 B纪念券(以下 简称B券).每个持有金券的顾客都有一个自己的帐户.金券的数目可以是一个 ...
随机推荐
- Less的模式匹配
Less的模式匹配 Less提供了一种机制,允许根据参数的值来改变 mixin的行为.比如,以下代码就可以让 .mixin 根据不同的 @switch 值而表现各异: .mixin (dark, @c ...
- azure备份虚拟机
备份 azure虚拟机 提前创建了一个linux虚拟机,位置是chinaeast. 如果我们需要备份的虚拟机分别在中国东部和北部,那么需要在两个位置都创建备份库. 创建库 登录经典门户,新建-> ...
- Python之可变类型与不可变类型
Python常见的数据类型有:数字 字符串 元组 列表 字典 不可变类型:数字 字符串 元组 可变类型: 列表 字典 a = 100 b = [100] def num1(x): x += x pri ...
- Ipython自动导入Numpy,pandas等模块
一.引言 最近在学习numpy,书上要求安装一个Ipythpn,可以自动导入Numpy,pandas等数据分析的模块,可是当我安装后,并不能自动导入numpy模块,还需要自己import.我就去查了一 ...
- ASE加密
密码学中的高级加密标准(Advanced Encryption Standard,AES),又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准.
- 51Nod 1084 矩阵取数问题 V2 双线程DP 滚动数组优化
基准时间限制:2 秒 空间限制:131072 KB 一个M*N矩阵中有不同的正整数,经过这个格子,就能获得相应价值的奖励,先从左上走到右下,再从右下走到左上.第1遍时只能向下和向右走,第2遍时只能向 ...
- HDU1541--Stars(树状数组)
Stars Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Subm ...
- Android破解学习之路(三)——Android游戏 切水果破解
经过前两篇破解教程,想必大家也是明白了破解的简单流程了. 先对APP进行试用,了解APP运行的大概流程,之后从APP中找出关键字(一般的关键字差不多都是支付失败),之后使用Androidkiller进 ...
- NOIP2017 小凯的疑惑
题目描述 小凯手中有两种面值的金币,两种面值均为正整数且彼此互素.每种金币小凯都有 无数个.在不找零的情况下,仅凭这两种金币,有些物品他是无法准确支付的.现在小 凯想知道在无法准确支付的物品中,最贵的 ...
- C语言写单链表的创建、释放、追加(即总是在最后的位置增加节点)
昨天周末给学妹讲了一些指针的知识,本来我对指针就是似懂非懂的状态,经过昨天一讲,我对指针的学习就更深刻了 果然给别人讲课也是学习的一个方法.加上最近复习数据结构,发现我的博客里没有链表的博文,所以趁这 ...