码迷,mamicode.com
首页 > 其他好文 > 详细

【BZOJ 1010】【HNOI 2008】玩具装箱 toy

时间:2015-05-25 22:28:56      阅读:161      评论:0      收藏:0      [点我收藏+]

标签:

借着这个题学习了一下dp的斜率优化,感觉这东西好神啊。。。
先说一下裸的O(n2)dp吧:

s[i]=i=1ic[i]

显然我们有
f[i]=mink=0i?1f[k]+(s[i]?s[k]?L)2

然而这个转移是O(n2) 的,在n=50000时无法接受,然后我们来考虑一下斜率优化。
我们设定j<k<i 但k比j优 那么
f[k]+(s[i]?s[k]+L)2<f[j]+(s[i]?s[j]+L)2

展开得
f[k]+s[i]2?2?s[i]?(s[k]+L)+(s[k]+L)2<f[j]+s[i]2?2?s[i]?(s[j]+L)+(s[j]+L)2

移项得
f[k]?f[j]+(s[k]+L)2?(s[j]+L)2<2?s[i]?(s[k]?s[j])

易得
f[k]?f[j]+(s[k]+L)2?(s[j]+L)22?s[i]?(s[k]?s[j])<s[i]

g[j,k]=f[k]?f[j]+(s[k]+L)2?(s[j]+L)22?s[i]?(s[k]?s[j])<s[i]
g[j][k]<s[i]kj
那么我们在更新f[i]时显然要从队列里选一个g[k][k+1]<s[i]
但当我们向队列中插入f[i]时呢?
设定j<k<ig[k][i]>g[j][k]
假设 f[k][i]<sum[i] 显然 ik 更优
反之 f[k][i]>sum[i] 则有 f[j][k]>f[k][i]>s[i] 显然 jk 更优
于是我们维护一个单调队列即可啦 code:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
long long f[50001],xi[50001],s[50001],queue[50001],L;
double g(int i,int j)
{
    return (f[j]-f[i]+(s[j]+L)*(s[j]+L)-(s[i]+L)*(s[i]+L))/(2.0*(s[j]-s[i]));
}
int main()
{
    int i,x,n,head,tail;
    scanf("%d%d",&n,&L); L++;
    xi[0]=s[0]=0; f[0]=0;
    for (i=1;i<=n;++i)
      {
        scanf("%d",&x);
        xi[i]=xi[i-1]+x;
        s[i]=xi[i]+i;
      }
    head=1; tail=1; queue[tail]=0;
    for (i=1;i<=n;++i)
      {
        while (head<tail&&g(queue[head],queue[head+1])<s[i]) head++;
        f[i]=f[queue[head]]+(s[i]-s[queue[head]]-L)*(s[i]-s[queue[head]]-L);
        while (head<tail&&g(queue[tail-1],queue[tail])>g(queue[tail],i)) tail--;
        queue[++tail]=i;
      }
    printf("%I64d\n",f[n]);
} 

【BZOJ 1010】【HNOI 2008】玩具装箱 toy

标签:

原文地址:http://blog.csdn.net/lcomyn/article/details/45974449

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!