bzoj [NOI2007]货币兑换Cash (cdq分治+斜率优化 )

1492: [NOI2007]货币兑换Cash

Time Limit: 5 Sec  Memory Limit: 64 MB

Submit: 2454  Solved: 1078

[Submit][Status][Discuss]

Description

Input

第一行两个正整数N、S,分别表示小Y 能预知的天数以及初始时拥有的钱数。 接下来N 行,第K 行三个实数AK、BK、RateK,意义如题目中所述

Output

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

Sample Input

3 100

1 1 1

1 2 2

2 2 3

Sample Output

225.000

按照cdq论文上的说法,应该写成n*lgn 。然而我强行每次都扫描凸包,复杂度多了多个一个lgn T_T。

#include<cstdio>
#include<cmath>
#include<queue>
#include<stack>
#include<string>
#include<cstring>
#include<iostream>
#include<map>
#include<vector>
#include<algorithm>
#include<stdlib.h>
#include<set>
#include<ctime>
#include<cmath>
#include<iomanip>
using namespace std;
typedef long long LL;
const int mmax  = 100010;
const int inf = 0x3fffffff;
const double eps = 1e-8;
double A[mmax],B[mmax],R[mmax];
double f[mmax];
double dp[mmax];

int sgn(double x)// ·ûºÅº¯Êý
{
    if(fabs(x)<eps)
        return 0;
    return x<0?-1:1;
}

struct Point
{
    double x,y;
    Point(double x=0.0,double y=0.0):x(x),y(y) {}
    void read()
    {
        scanf("%lf %lf",&x,&y);
    }
};
typedef Point Vector;
Vector operator + (Vector A,Vector B)
{
    return Vector(A.x+B.x,A.y+B.y);
}

Vector operator - (Point A,Point B)
{
    return Vector(A.x-B.x,A.y-B.y);
}
Vector operator * (Vector A,double p)
{
    return Vector(A.x*p,A.y*p);
}
Vector operator / (Vector A,double p)
{
    return Vector(A.x/p,A.y/p);
}

bool operator < (const Point &a,const Point &b)
{
    return a.x<b.x || (a.x==b.x&&a.y<b.y);
}
//ÔËË㲿·Ö
double Dot(Vector A,Vector B)
{
    return A.x*B.x+A.y*B.y;
}
double Cross(Vector A,Vector B)
{
    return A.x*B.y-A.y*B.x;
}

double x(int i)
{
    return dp[i]*R[i]/f[i];
}
double y(int i)
{
    return dp[i]/f[i];
}

bool cmp(int i,int j)
{
    return A[i]*B[j]>A[j]*B[i];
}

int ConvexHull(Point *p,int n,Point *Poly)
{
    sort(p,p+n);
    int m=0;
    for(int i=n-1;i>=0;i--)
    {
        while(m>1 && Cross(Poly[m-1]-Poly[m-2],p[i]-Poly[m-2]) <=0 ) m--;
        Poly[m++]=p[i];
    }
    return m;
}
Point P[mmax],Poly[mmax];
int tmp[mmax];
void cdq(int l,int r)
{
    if(l==r)
    {
        dp[l]=max(dp[l],dp[l-1]);
        return ;
    }

    int mid=(l+r)>>1;
    cdq(l,mid);
    int cnt=0;
    for(int i=l;i<=mid;i++)
        P[cnt++]=Point(x(i),y(i));

    cnt=ConvexHull(P,cnt,Poly);
    for(int i=mid+1;i<=r;i++)
        tmp[i]=i;
    sort(tmp+mid+1,tmp+r+1,cmp);

    int i=0,j=mid+1;

    while(j<=r)
    {
        while(i<cnt-1 && (Poly[i].y-Poly[i+1].y )*B[tmp[j]] < -1.0*(Poly[i].x-Poly[i+1].x)*A[tmp[j]]  )
            i++;
        dp[tmp[j]]=max(dp[tmp[j]],A[tmp[j]]*Poly[i].x+B[tmp[j]]*Poly[i].y);
        j++;
    }
    cdq(mid+1,r);

}
int main()
{

    int n,s;
    cin>>n>>s;
    for(int i=1;i<=n;i++)
    {
        scanf("%lf %lf %lf",&A[i],&B[i],&R[i]);
        f[i]=A[i]*R[i]+B[i];
    }
    memset(dp,0,sizeof dp);
    dp[0]=1.0*s;
    cdq(1,n);

    double ans=0;
    for(int i=1;i<=n;i++)
        ans=max(ans,dp[i]);
    printf("%.3lf\n",ans);

    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-12-14 07:51:01

bzoj [NOI2007]货币兑换Cash (cdq分治+斜率优化 )的相关文章

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

1492: [NOI2007]货币兑换Cash Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 5541  Solved: 2228[Submit][Status][Discuss] Description 小Y最近在一家金券交易所工作.该金券交易所只发行交易两种金券:A纪念券(以下简称A券)和 B纪念券(以下 简称B券).每个持有金券的顾客都有一个自己的帐户.金券的数目可以是一个实数.每天随着市场的起伏波动, 两种金券都有自己当时的价值,即每一单位金

BZOJ 1492 NOI 2007 货币兑换Cash CDQ分治+斜率优化DP

题目大意:有两种金券,A和B.每一天有一个rate值,表示购入的比例:还有每一天AB金券的售价.现在给出初始的钱数,问最后能够获得多少钱. 思路:这算是神题了吧,啃论文啃别人代码将近一天才算有点明白. 首先题目中说的可以买一部分或者卖一部分是扯淡的,因为为了最大获利一定要全部买入,全部卖出.朴素的DP方程就好弄了. 设f[i]为第i天最多的B券的数量.那么f[i] = (rate[j] * f[j] * a[i] + f[j] * b[i]) / (rate[i] * a[i] + b[i])

BZOJ 3963: [WF2011]MachineWorks [CDQ分治 斜率优化DP]

传送门 当然了WF的题uva hdu上也有 你的公司获得了一个厂房N天的使用权和一笔启动资金,你打算在这N天里租借机器进行生产来获得收益.可以租借的机器有M台.每台机器有四个参数D,P,R,G.你可以在第D天花费P的费用(当然,前提是你有至少P元)租借这台机器,从第D+1天起,操作机器将为你产生每天G的收益.在你不再需要机器时,可以将机器卖掉,一次性获得R的收益.厂房里只能停留一台机器.不能在购买和卖出机器的那天操作机器,但是可以在同一天卖掉一台机器再买入一台.在第N+1天,你必须卖掉手上的机器

【uoj#244】[UER #7]短路 CDQ分治+斜率优化dp

题目描述 给出 $(2n+1)\times (2n+1)$ 个点,点 $(i,j)$ 的权值为 $a[max(|i-n-1|,|j-n-1|)]$ ,找一条从 $(1,1)$ 走到 $(2n+1,2n+1)$ 的路径,使得经过的点(包括起点和终点)权值和最小.求这个权值和. 输入 第一行一个正整数 $n$ . 第二行 $n+1$ 个正整数 $a[0],a[1],…,a[n]$ ,表示从内到外每层的中继器的延时值. 输出 输出一行一个数表示改造后的最短引爆时间. 样例输入 99 5 3 7 6 9

[BZOJ 1492][NOI2007]货币兑换Cash(CDQ分治+斜率优化Dp)

Description 小Y最近在一家金券交易所工作.该金券交易所只发行交易两种金券:A纪念券(以下简称A券)和 B纪念券(以下 简称B券).每个持有金券的顾客都有一个自己的帐户.金券的数目可以是一个实数.每天随着市场的起伏波动, 两种金券都有自己当时的价值,即每一单位金券当天可以兑换的人民币数目.我们记录第 K 天中 A券 和 B券 的 价值分别为 AK 和 BK(元/单位金券).为了方便顾客,金券交易所提供了一种非常方便的交易方式:比例交易法 .比例交易法分为两个方面:(a)卖出金券:顾客提

【BZOJ3963】[WF2011]MachineWorks cdq分治+斜率优化

[BZOJ3963][WF2011]MachineWorks Description 你是任意性复杂机器公司(Arbitrarily Complex Machines, ACM)的经理,公司使用更加先进的机械设备生产先进的机器.原来的那一台生产机器已经坏了,所以你要去为公司买一台新的生产机器.你的任务是在转型期内尽可能得到更大的收益.在这段时间内,你要买卖机器,并且当机器被ACM公司拥有的时候,操控这些机器以获取利润.因为空间的限制,ACM公司在任何时候都只能最多拥有一台机器. 在转型期内,有若

HDU 3842 Machine Works cdq分治 斜率优化

本题是利用cdq分治  实现斜率优化的一个题目 斜率优化之前做的几个题都是斜率单调,并且插入点时由于点在某一维单调,所以仅仅操作队首和队尾就能完成优化了 但是本题显然不是 主要参考了两个东西 从<Cash>谈一类分治算法的应用 (Day1)cdq分治相关 这两个直接在百度上搜 ,第一个出来的就是 本题的题意是 一个公司获得了一个厂房n(10^5)天的使用权 和一笔启动资金C(10^9),准备在n天里租借机器生产来获得收益 可以租借的机器有M(10^5)个,每个机器有四个值,D,P,R,G (D

bzoj3672/luogu2305 购票 (运用点分治思想的树上cdq分治+斜率优化dp)

我们都做过一道题(?)货币兑换,是用cdq分治来解决不单调的斜率优化 现在它放到了树上.. 总之先写下来dp方程,$f[i]=min\{f[j]+(dis[i]-dis[j])*p[i]+q[i]\} ,j是i的祖先,dis[i]-dis[j]<=l[i]$ ,其中dis[i]表示1号点到i号点的距离 可以很明显的看出斜率优化,但我们要放到树上做 于是就运用点分治的思想来找重心(正如普通的cdq是找重点一样) 步骤是这样的: 1.对于根为x的一个子树,我们先找到它的重心rt 2.把rt的子树刨掉

【BZOJ1492】[NOI2007]货币兑换Cash 斜率优化+cdq分治

[BZOJ10492][NOI2007]货币兑换Cash Description 小Y最近在一家金券交易所工作.该金券交易所只发行交易两种金券:A纪念券(以下简称A券)和 B纪念券(以下简称B券).每个持有金券的顾客都有一个自己的帐户.金券的数目可以是一个实数.每天随着市场的起伏波动,两种金券都有自己当时的价值,即每一单位金券当天可以兑换的人民币数目.我们记录第 K 天中 A券 和 B券 的价值分别为 AK 和 BK(元/单位金券).为了方便顾客,金券交易所提供了一种非常方便的交易方式:比例交易