【BZOJ1096】仓库建设,斜率优化DP练习

传送门
写在前面:前来报道的学弟
思路:这是学习斜率优化后完全自己独立处理出的第一个题吧,感觉自己还是太弱,这么就初步理解斜率优化。
先推转移方程,这个还是比较好弄得
f[i]=c[i]+min(f[j]+ik=j+1p[k](s[i]s[k]))
看似是一个 O(n3) ,但我们把sigma里的东西拆开,处理前缀和
sum1[i]=ij=1p[j]s[j]
sum2[i]=ij=1p[j]
那么转移就是
f[i]=c[i]+min(f[j]+s[i](sum2[i]sum2[j])(sum1[i]sum1[j]))
O(n2) 可以得20分
正解是 O(n)
假设x>y且由x比y转移更优
然后一顿化简,得到
(f[x]f[y]+sum1[x]sum1[y])/(sum2[x]sum2[y])<s[i]
接下来就代码了
注意:
有符号整型把我吓了一跳,还以为有负数个货物……
代码:

#include<bits/stdc++.h>
#define LL long long
#define M 1000002
using namespace std;
int n,head=1,tail=1;
int s[M],c[M],p[M],q[M];
LL f[M],sum1[M],sum2[M];
int in()
{
    int t=0,f=1;char ch=getchar();
    while (ch>'9'||ch<'0')
    {
        if (ch=='-') f=-1;
        ch=getchar();
    }
    while (ch>='0'&&ch<='9') t=(t<<3)+(t<<1)+ch-'0',ch=getchar();
    return f*t;
}
double Get(int x,int y)
{
    return (double)(f[x]-f[y]+(sum1[x]-sum1[y]))/(double)(sum2[x]-sum2[y]);
}
main()
{
    n=in();
    for (int i=1;i<=n;i++)
    s[i]=in(),p[i]=in(),c[i]=in(),
    sum1[i]=sum1[i-1]+(LL)p[i]*s[i],
    sum2[i]=sum2[i-1]+p[i];
    for (int i=1;i<=n;i++)
    {
        while (head<tail&&Get(q[head+1],q[head])<(double)s[i]) head++;
        f[i]=f[q[head]]+c[i]+s[i]*(sum2[i]-sum2[q[head]])-(sum1[i]-sum1[q[head]]);
        while (head<tail&&Get(i,q[tail])<Get(q[tail],q[tail-1])) tail--;
        q[++tail]=i;
    }
    printf("%lld",f[n]);
}

你可能感兴趣的:(【BZOJ1096】仓库建设,斜率优化DP练习)