• bzoj1492 NOI2007 货币兑换Cash


    题目描述

    题解:

    题目都提示了,

    很明显要导一波式子:

    $$dp[i]=max( dp[i-1] , frac{ dp[j] } { A[j]*R[j]+B[j] } * (A[i]*R[j]+B[i]))$$

    后面那个东西相当与将第j天的R[j]个A和1个B绑在一起。

    $dp[i-1]$没什么好说的,关键是后面那个。

    看起来还可以提一下。

    $$dp[i]=frac{dp[j]}{A[j]*R[j]+B[j]}*(A[i]*R[j]+B[i])$$

    把右面$A[i]$移项:

    $$frac{dp[i]}{A[i]}=frac{dp[j]*R[j]}{A[j]*R[j]+B[j]}+frac{B[i]}{A[i]}*frac{dp[j]}{A[j]*R[j]+B[j]}$$

    再移一下:

    $$frac{dp[j]*R[j]}{A[j]*R[j]+B[j]}=-frac{B[i]}{A[i]}*frac{dp[j]}{A[j]*R[j]+B[j]}+frac{dp[i]}{A[i]}$$

    现在让$b$项最大,维护斜率递减的上凸包。

    但是x没有单调性啊……

    于是就有两种处理方法。

    第一种是$splay$在线强插,比较恶心;

    第二种是$cdq$离线处理,非常好写。

    由于我们要尽可能优化时间,可以考虑每次更新之前让左区间的$x$有序,右区间的$k$有序。

    这样的话左边$O(n)$建凸包,右边$O(n)$匹配。

    但是每次都要排序啊……

    我们不妨先将整个区间关于$k$排序,然后分治前按编号分好,这样可以保证右边的k一定是单调的。

    这样整体就是$O(nlogn)$了。

    代码:

    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define db double
    #define N 100050
    const db eps = 1e-8;
    const db inf = 1e10;
    int n;
    db dp[N];
    struct node
    {
        db a,b,r,x,y,k;
        int id;
    }p[N],tmp[N];
    db slop(node n1,node n2)
    {
        if(fabs(n1.x-n2.x)<=eps)return inf;
        return (n1.y-n2.y)/(n1.x-n2.x);
    }
    bool cmpid(node n1,node n2)
    {
        return n1.id<n2.id;
    }
    bool cmpk(node n1,node n2)
    {
        return n1.k<n2.k;
    }
    void Sort(int l,int r)//cmp x
    {
        int mid = (l+r)>>1;
        int i=l,j = mid+1,k = l-1;
        while(i<=mid&&j<=r)
        {
            while(i<=mid&&p[i].x<=p[j].x)tmp[++k]=p[i++];
            while(j<=r&&p[i].x>p[j].x)tmp[++k]=p[j++];
        }
        while(i<=mid)tmp[++k]=p[i++];
        while(j<=r)tmp[++k]=p[j++];
        for(i=l;i<=r;i++)p[i]=tmp[i];
    }
    void divi(int l,int r)
    {
        int mid = (l+r)>>1;
        int i=l-1,j=mid;
        for(int k=l;k<=r;k++)
        {
            if(p[k].id<=mid)tmp[++i]=p[k];
            else tmp[++j]=p[k];
        }
        for(int k=l;k<=r;k++)p[k]=tmp[k];
    }
    int sta[N],tl;
    void cdq(int l,int r)
    {
        if(l==r)
        {
            dp[l] = max(dp[l],dp[l-1]);
            p[l].x = dp[l]/(p[l].a*p[l].r+p[l].b);
            p[l].y = p[l].x*p[l].r;
            return ;
        }
        int mid = (l+r)>>1;
        divi(l,r);
        cdq(l,mid);
        tl = 0;
        for(int i=l;i<=mid;i++)
        {
            while(tl>=2&&slop(p[sta[tl]],p[i])+eps>slop(p[sta[tl]],p[sta[tl-1]]))tl--;
            sta[++tl] = i;
        }
        for(int i=mid+1;i<=r;i++)
        {
            while(tl>=2&&slop(p[sta[tl]],p[sta[tl-1]])<p[i].k+eps)tl--;
            dp[p[i].id] = max(dp[p[i].id],p[sta[tl]].x*p[i].b+p[sta[tl]].y*p[i].a);
        }
        cdq(mid+1,r);
        Sort(l,r);
    }
    int main()
    {
        scanf("%d%lf",&n,&dp[0]);
        for(int i=1;i<=n;i++)
        {
            scanf("%lf%lf%lf",&p[i].a,&p[i].b,&p[i].r);
            p[i].k = -p[i].b/p[i].a;p[i].id = i;
        }
        sort(p+1,p+1+n,cmpk);
        cdq(1,n);
        printf("%.3lf
    ",dp[n]);
        return 0;
    }
  • 相关阅读:
    "科林明伦杯"哈理工第九届——分布式服务(概率期望+思维)
    Nim游戏——简单博弈论
    acwing 1252搭配购买(并查集 + 01背包 )
    [LeetCode] 67. Add Binary
    [LeetCode] 415. Add Strings
    [LeetCode] 43. Multiply Strings
    [LeetCode] 412. Fizz Buzz
    [LeetCode] 201. Bitwise AND of Numbers Range
    [LeetCode] 389. Find the Difference
    [LeetCode] 326. Power of Three + 342. Power of Four
  • 原文地址:https://www.cnblogs.com/LiGuanlin1124/p/10193646.html
Copyright © 2020-2023  润新知