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\n",dp[n]);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/LiGuanlin1124/p/10193646.html