BZOJ 1492 货币兑换 cdq分治或平衡树维护凸包

Posted gccbuaa

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 1492 货币兑换 cdq分治或平衡树维护凸包相关的知识,希望对你有一定的参考价值。

题意:链接

方法:cdq分治或平衡树维护凸包

解析:

这道题我拒绝写平衡树的题解,我仅仅想说splay不要写挂,insert边界条件不要忘。del点的时候不要脑抽d错。有想写平衡树的去看140142或者留言我。

首先这道题能推出个表达式

f[i]代表第i天最大收益。

xx[i]表示将第i天的钱都买A的数量

yy[i]表示将第i天的钱都买B的数量

所以f[i]=max(f[i?1],p[i].a?xx[j]+p[i].b?yy[j])j<i

所以我们要维护这个n^2的递推式

又知道f[i]是由小于i的j更新的,

但方程要进一步写一下

yy[i]=(-p[i].a/p[i].b)*xx[i]+f[i]/p[i].b

所以我们要得到最大截距所以能够依照斜率递减维护一个凸包来找某一确定直线与这个凸包截得的最大截距,也就是斜率第一个小于等于它的某个凸包上的点。

之后的部分就是採用cdq维护或者平衡树

平衡树真是一个噩梦

代码:

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 100010
#define eps 1e-9
#define INF 0x7fffffff
using namespace std;
typedef long long ll;
int n;
double f[N];
int stack[N];
struct node
{
    double x,y,a,b,rate,k;
    int w;
}p[N],t[N];
int cmp(node a,node b)
{
    return a.k>b.k;
}
double getk(int a,int b)
{
    if(!b)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-1],f[l]);
        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 mid=(l+r)>>1;
    int l1=l,l2=mid+1,pt=1;
    for(int i=l;i<=r;i++)
    {
        if(p[i].w<=mid)t[l1++]=p[i];
        else t[l2++]=p[i];
    }
    for(int i=l;i<=r;i++)p[i]=t[i];
    solve(l,mid);
    int top=0;
    for(int i=l;i<=mid;i++)
    {
        while(top>1&&getk(stack[top-1],stack[top])<=getk(stack[top],i))top--;
        stack[++top]=i;
    }
    stack[++top]=0;
    for(int i=mid+1;i<=r;i++)
    {
        while(pt<top&&getk(stack[pt],stack[pt+1])>p[i].k)pt++;
        f[p[i].w]=max(f[p[i].w],p[stack[pt]].x*p[i].a+p[stack[pt]].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()
{
    scanf("%d%lf",&n,&f[0]);
    for(int i=1;i<=n;i++)
    {
        scanf("%lf%lf%lf",&p[i].a,&p[i].b,&p[i].rate);
        p[i].k=-p[i].a/p[i].b;
        p[i].w=i;
    }
    sort(p+1,p+1+n,cmp);
    solve(1,n);
    printf("%.3lf\n",f[n]);
}

以上是关于BZOJ 1492 货币兑换 cdq分治或平衡树维护凸包的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ1492 货币兑换 CDQ分治优化DP

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

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

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

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

[BZOJ1492] [NOI2007]货币兑换Cash 斜率优化+cdq/平衡树维护凸包