BZOJ1492:[NOI2007]货币兑换——题解

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ1492:[NOI2007]货币兑换——题解相关的知识,希望对你有一定的参考价值。

http://www.lydsy.com/JudgeOnline/problem.php?id=1492

(题目描述太长了不粘贴了……)

………………………………………………………

是自己做的

抄开心

……………………………………………………………

所以……emm,简单的dp就是:

f(i)=max(a[i]*x[j]+b[i]*y[j])

其中x和y表示在第i 天,用最多的钱能够换成的A券和B券。

完后……这怎么斜率优化啊……如果把x和y看做点来斜率优化的话它们也没有单调性啊。

推荐一个博客,可以在这里看推导式子(其实是我懒):http://blog.csdn.net/lych_cys/article/details/50674962

平衡树固然可以解决问题,但是CDQ分治在这种问题上显得更加睿智。

我们完全可以对其变成一维排a/b,二维CDQ一下它们出现时间t,三维求f。把每个点看做询问和添加操作即可。

剩下的就是单调队列基础操作了。

题解瞎编完了hhh

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
typedef double dl;
const int N=1e5+5;
struct node{
    dl x,y;
    inline bool operator <(const node &b)const{
        return x<b.x||x==b.x&&y<b.y;
    }
}p[N],que[N];
int n,t[N],tmp[N];
dl f[N],a[N],b[N],rate[N],ans;
inline bool cmp(int x,int y){
    return a[x]*b[y]<a[y]*b[x];
}
inline bool slope(node k,node j,node i){
    return (j.x-i.x)*(k.y-i.y)-(j.y-i.y)*(k.x-i.x)<=0;
}
inline dl suan(node j,int i){
    return j.x*a[i]+j.y*b[i];
}
void cdq(int l,int r){
    if(l==r){
        f[l]=max(f[l],f[l-1]);
        ans=max(ans,f[l]);
        p[l].y=f[l]/(a[l]*rate[l]+b[l]);
        p[l].x=p[l].y*rate[l];
        return;
    }
    int mid=(l+r)>>1,idx1=l,idx2=mid+1,ql=1,qr=0;
    for(int i=l;i<=r;i++){
        if(t[i]<=mid)tmp[idx1++]=t[i];
        else tmp[idx2++]=t[i];
    }
    for(int i=l;i<=r;i++)t[i]=tmp[i];
    cdq(l,mid);
    for(int i=l;i<=mid;i++){
        while(qr>1&&slope(que[qr-1],que[qr],p[i]))qr--;
        que[++qr]=p[i];
    }
    for(int i=mid+1;i<=r;i++){
        int j=t[i];
        while(ql<qr&&suan(que[ql],j)<=suan(que[ql+1],j))ql++;
        f[j]=max(f[j],suan(que[ql],j));
    }
    cdq(mid+1,r);
    if(l==1&&r==n)return;
    ql=l,idx1=l,idx2=mid+1;
    while(ql<=r){
        if(idx2>r||idx1<=mid&&p[idx1]<p[idx2])que[ql++]=p[idx1++];
        else que[ql++]=p[idx2++];
    }
    for(int i=l;i<=r;i++)p[i]=que[i];
    return;
}
int main(){
    scanf("%d%lf",&n,&f[0]);
    for(int i=1;i<=n;i++){
        scanf("%lf%lf%lf",&a[i],&b[i],&rate[i]);
        t[i]=i;
    }
    sort(t+1,t+n+1,cmp);
    cdq(1,n);
    printf("%.3lf\\n",ans);
    return 0;
}

+++++++++++++++++++++++++++++++++++++++++++

+本文作者:luyouqi233。               +

+欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+

+++++++++++++++++++++++++++++++++++++++++++

以上是关于BZOJ1492:[NOI2007]货币兑换——题解的主要内容,如果未能解决你的问题,请参考以下文章

bzoj1492: [NOI2007]货币兑换Cash

bzoj1492 [NOI2007]货币兑换Cash

BZOJ1492:[NOI2007]货币兑换——题解

BZOJ1492: [NOI2007]货币兑换Cash

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

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

(c)2006-2024 SYSTEM All Rights Reserved IT常识