BZOJ 4073 Wf2014 Buffed Buffet 斜率优化

题目大意:给定 d 种食物,食物分两个类型:离散食物和连续食物
离散食物只能按份供应,每种食物有一个质量w
连续食物可以食用任意质量
每种食物有一个初始美味值 t 和一个美味值衰减系数 t
对于一种离散食物,如果你吃了 N 份,那么获得的美味值为 Ni=1(t(i1)t)
对于一种连续食物,如果你吃的质量为 X ,那么获得的美味值为 X0(txt)dx
现在你必须吃总质量为 W 的食物,求最多获得的美味值(可以为负),无解输出”impossible”
d250,W104,0t,t104

由于 W104 ,我们可以考虑枚举离散食物吃多少,然后将离散食物和连续食物分开考虑

对于离散食物,我们令 fi 表示吃质量为 i 的离散食物能获得的最大美味值
枚举每种食物更新 fi ,有DP方程:
fi=fj+(2t(ijw1)t)ijw2(0ji,ij(mod w))
把这个式子化简可以斜率优化,于是离散食物就可以求了

对于连续食物,显然我们要用贪心的思想来吃
将所有连续食物按照 t 从大到小排序,首先我们肯定要吃最大的
随着最大的食物的美味值在不断下降,总有一时刻这种食物的美味值会和第二大的一样
这时候我们显然要把两种食物混合着吃,那么我们不妨将这两种食物合并成一种美味值衰减系数为 11t1+1t2 的食物
然后继续吃下去就行了

时间复杂度 O(dWlog2W)

注意BZ上的数据精度不够 用long double会挂掉一个点

#include <cstdio>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <algorithm>
#define M 10100
#define EPS 1e-7
#define INF 1e30
using namespace std;
typedef double ld;
int n,m;
long long f[M];
pair<double,double> stack[300];int top;
double sum[M];
bool able[M];
namespace Convex_Hull{
    struct Point{
        long long x,y;
        Point() {}
        Point(long long _,long long __):
            x(_),y(__) {}
        friend double Get_Slope(const Point &p1,const Point &p2)
        {
            return (double)(p1.y-p2.y)/(p1.x-p2.x);
        }
    }stack[M];int top;
    double slope[M];
    void Initialize()
    {
        top=0;
    }
    void Insert(const Point &p)
    {
        double s=top?Get_Slope(stack[top],p):0;
        while( top>=2 && -slope[top]<s )
            s=Get_Slope(stack[--top],p);
        stack[++top]=p;slope[top]=-s;
    }
    Point Query(double s)
    {
        return stack[lower_bound(slope+2,slope+top+1,-s-EPS)-slope-1];
    }
}
void Slope_Optimized_DP(long long w,long long t,long long dt)
{
    static long long g[M];
    int i,j;
    long long _i;
    memset(g+1,0,sizeof(g[0])*m);
    for(i=0;i<w;i++)
    {
        Convex_Hull::Initialize();
        for(j=0;(_i=i+j*w)<=m;j++)
        {
            if(able[_i])
                Convex_Hull::Insert( Convex_Hull::Point( j , 2*f[_i] - dt*j*j - 2*t*j ) );
            if(!Convex_Hull::top)
                g[_i] = 0xefefefefefefefefll;
            else 
            {
                long long _j = Convex_Hull::Query( - (2*j-1)*dt ).x;
                g[_i] = f[i+_j*w] + ( 2*t - ( (j-_j)-1 ) * dt ) * ( j-_j ) / 2 ;
            }
        }
    }
    for(i=w;i<=m;i++)
        able[i]|=able[i-w];
    memcpy(f+1,g+1,sizeof(f[0])*m);
}
/* void Unoptimized_DP(long long w,long long t,long long dt) { int i,j; for(i=1;i*w<=m;i++) for(j=m;j>=w;j--) if(able[j-w]) f[j]=max(f[j],f[j-w]+t-(i-1)*dt); for(i=w;i<=m;i++) able[i]|=able[i-w]; } */
int main()
{
    int i,j,w,t,dt;
    char p[10];
    cin>>n>>m;
    memset(f,0xef,sizeof f);f[0]=0;able[0]=true;
    for(i=1;i<=n;i++)
    {
        scanf("%s",p);
        if(p[0]=='D')
        {
            scanf("%d%d%d",&w,&t,&dt);
            Slope_Optimized_DP(w,t,dt);
            //Unoptimized_DP(w,t,dt);
        }
        else
        {
            scanf("%d%d",&t,&dt);
            stack[++top]=pair<double,double>(t,dt);
        }
    }
    if(!top)
    {
        if(!able[m])
            puts("impossible");
        else
            cout<<f[m]<<".000000000"<<endl;
        return 0;
    }
    sort(stack+1,stack+top+1);
    double l=0,r=0,slope=INF,sum=0;
    for(i=1;i<=top>>1;i++)
        swap(stack[i],stack[top-i+1]);
    for(j=1,i=1;i<=top;i++)
    {
        slope=1.0/(1.0/slope+1.0/stack[i].second);
        l=r;r=i==top||slope<EPS?m+1:l+(stack[i].first-stack[i+1].first)/slope;
        for(;j<=r+EPS&&j<=m;j++)
            ::sum[j]=sum+(j-l)*(stack[i].first*2-(j-l)*slope)/2;
        sum+=(r-l)*(stack[i].first*2-(r-l)*slope)/2;
        if(slope<EPS) break;
    }
    double ans=-INF;
    for(i=0;i<=m;i++)
        if(able[i])
            ans=max(ans,f[i]+::sum[m-i]);
    cout<<fixed<<setprecision(9)<<ans<<endl;
    return 0;
}

你可能感兴趣的:(斜率优化,bzoj,4073)