[bzoj1096] [ZJOI2007]仓库建设

有n个点,每个点有p和c和坐标x,现在每个点可以选择建一座仓库,花费c块软妹币,或者运到后面的仓库,花费坐标差*p块软妹币

求最小花费 n<=1,000,000

点j连到点i的花费是(si-sj)*pj=si*pj -sj*pj

令gi=-si*pi

如果j比k优秀,那么f[j]+g[j..i]+si*p[j..i]<f[k]+g[k..i]+si*p[k..i]

(f[j]+g[j]-f[k]-g[k])/(p[j]-p[k])<s[i]

斜率优化

#include<iostream>
#include<cstdio>
#define ll long long
#define MAXN 1000000
#define INF 200000000
#define eps 1e-8
using namespace std;
int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}
int n,top=0,tail=1;+
ll f[MAXN+5],p[MAXN+5],c[MAXN+5],s[MAXN+5],pp[MAXN+5],g[MAXN+5];
int q[MAXN+5];

double geth(int x,int y)
{
    return (double)(g[x]-g[y])/(double)(p[x]-p[y]-eps);
}

int get(int i)
{
    while(top-tail>=1&&geth(q[tail+1],q[tail])<s[i]) tail++;
    return q[tail];
}

void ins(int i)
{
    while(top-tail>=1&&geth(q[top],q[top-1])>geth(i,q[top]))top--;
    q[++top]=i;
}

int main()
{
    n=read();
    for(int i=1;i<=n;i++)s[i]=read(),p[i]=read(),c[i]=read();
    for(int i=1;i<=n;i++)pp[i]=pp[i-1]-p[i]*s[i],p[i]+=p[i-1];
    for(int i=1;i<=n;i++)
    {
        int x=get(i);
        f[i]=f[x]+s[i]*(p[i-1]-p[x])+pp[i-1]-pp[x]+c[i];
        f[i]=min(f[i],s[i]*(p[i-1])+pp[i-1]+c[i]);
        g[i]=f[i]-pp[i];
        ins(i);
    }
    cout<<f[n];
    return 0;
}

 

posted @ 2017-02-28 13:43  FallDream  阅读(273)  评论(0编辑  收藏  举报