【BZOJ】1096 [ZJOI2007]仓库建设

【算法】DP+斜率优化

【题解】状态转移方程:f[i]=min(f[j]+g(i+1,j-1))+c[i]

关键在于如何O(1)计算g(i+1,j-1)。

推导过程:http://blog.csdn.net/PoPoQQQ/article/details/40504949

当d(j,k)中j<k且k更优时,得到斜率不等式:

(f[j]-f[k]+sumpx[j]-sumpx[k])/(sump[j]-sump[k])<x[i]

于是斜率优化。

斜率优化:http://www.cnblogs.com/onioncyc/p/6113450.html

【细节】

1.是while不是if。。。

2.p[i]*x[i]*1ll。。。

3.转double运算优先度高于除法的样子。

#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn=1000010;
int q[maxn],x[maxn],p[maxn],c[maxn],n;
ll f[maxn],sump[maxn],sumpx[maxn];
double calc(int j,int k)
{return (double)(f[j]-f[k]+sumpx[j]-sumpx[k])/(sump[j]-sump[k]);}//important3
ll g(int i,int j)
{return x[i]*(sump[i-1]-sump[j])-(sumpx[i-1]-sumpx[j]);}
int main()
{
    scanf("%d",&n);
    sump[0]=sumpx[0]=0;
    for(int i=1;i<=n;i++)
     {
         scanf("%d%d%d",&x[i],&p[i],&c[i]);
         sump[i]=sump[i-1]+p[i];
         sumpx[i]=sumpx[i-1]+1ll*p[i]*x[i];//important2
     }
    int head=1,tail=1;q[1]=0;f[0]=0;
    for(int i=1;i<=n;i++)
     {
         while(head<tail&&calc(q[head],q[head+1])<x[i])head++;
         f[i]=f[q[head]]+g(i,q[head])+c[i];
         while(head<tail&&calc(q[tail-1],q[tail])>calc(q[tail],i))tail--;//important1
         q[++tail]=i;
     }
    printf("%lld",f[n]);
    return 0;
}
View Code

 

posted @ 2016-12-05 19:19  ONION_CYC  阅读(127)  评论(0编辑  收藏