BZOJ 1492: [NOI2007]货币兑换Cash

看题面戳我

60分做法:有提示得,每次必须买完或者卖完,感觉像dp

f[i]表示前i天赚取的最多钱

f_{i}=max(f_{i-1},max(x_{j}*a_{i}+y_{j}*b_{i}))

其中 y_{j}=\frac{f_{j}}{a_{j}*r_{j}+b_{j}}x_{j}=y_{j}*r_{j}

#include<cstdio>
#include<iostream>
using namespace std;

const int N=1e5+5;
int n;
double f[N],a[N],b[N],r[N];
 
int main()
{
	scanf("%d%lf",&n,&f[0]);
	for(int i=1;i<=n;i++) 
		scanf("%lf%lf%lf",&a[i],&b[i],&r[i]);
	for(int i=1;i<=n;i++)
	{
		f[i]=f[i-1];
		for(int j=1;j<i;j++) 
			f[i]=max(f[i],(r[j]*a[i]+b[i])*f[j]/(a[j]*r[j]+b[j])); 
	}
	printf("%.3lf\n",f[n]);
	return 0;
 } 

100分做法:

这个式子很像斜率

y_{i}=\frac{-a_{i}}{b_{i}}*x_{i}+\frac{f_{i}}{b_{i}}

所以就求截距最大(截距:一条直线与y轴的交点的纵坐标)

维护一个上凸包

x无序,y也无序,怎么办呢?

1、平衡树维护

2、cdq分治

菜鸡毫不犹豫选了cdq

#include<cmath>
#include<cstdio>
#include<iostream>
#define db double
using namespace std;

const int N=1e5+5;
const db eps=1e-7,INF=1e18;
int n,qu[N]; 
db f[N],a[N],b[N],r[N];
struct A{ int id; db k,x,y; } q[N],t[N];

inline db g(int i,int j)
{
    if(abs(q[j].x-q[i].x)<eps) return q[i].y<q[j].y?INF:-INF;
    return (q[i].y-q[j].y)/(q[i].x-q[j].x);
}

void work(int l,int r)
{
    if(l==r)
    {
        f[l]=max(f[l],f[l-1]);
        q[l].x*=f[l]; q[l].y*=f[l]; 
	    return;
    }  
    int mid=l+r>>1;
    work(l,mid); 
    int top=1; qu[1]=0;
    for(int i=l;i<=mid;i++)
    {
        while(top>1&&g(qu[top-1],qu[top])<=g(qu[top-1],i)) top--;
        qu[++top]=i;    
    }
    for(int i=mid+1;i<=r;++i)
    {
        int L=2,R=top,s=1;
        while(L<=R)
        {
            int M=L+R>>1;
            if(g(qu[M-1],qu[M])>q[i].k) L=M+1,s=M;
                else R=M-1;
        }   
        f[i]=max(f[i],(-q[qu[s]].x*q[i].k+q[qu[s]].y)*b[i]);   
    }       
    work(mid+1,r);
    int i=l,j=mid+1,k=l;
    while(i<=mid&&j<=r)
	{
        if(q[i].x<=q[j].x) t[k++]=q[i++];
		    else t[k++]=q[j++];  
    }
    while(i<=mid) t[k++]=q[i++];
    while(j<=r) t[k++]=q[j++];
    for(int i=l;i<=r;++i) q[i]=t[i];
}

int main()
{
	scanf("%d%lf",&n,&f[0]);
    for(int i=1;i<=n;i++) 
    {
        scanf("%lf%lf%lf",&a[i],&b[i],&r[i]);
        q[i]=(A){i,-a[i]/b[i],r[i]/(a[i]*r[i]+b[i]),(db)1/(a[i]*r[i]+b[i])}
    }
    work(1,n); 
    printf("%.3lf\n",f[n]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/YYHS_WSF/article/details/84744949