bzoj1010

1010 玩具装箱toy

   易得O(n^2)dp,转移式为dp[i]=min{dp[j]+(i-j-1+sum[i]-sum[j]-L)^2},所以我们考虑用斜率来优化这个dp式子,设sum[i]为前缀和,f[i]=sum[i]+ic=L+1,考虑j,k<i,当(dp[j]+f[j]^2-dp[k]-f[k]^2)/(f[j]-f[k])<=2*(f[i]-c)j的答案比k优,因为f[i]-c单调增,可以可用单调队列维护单调增的斜率,对于每个i,当前队列首,若斜率(l+1,l)<2*(f[i]-c)l+1肯定比l优,所以将l踢出队列,然后用q[l]的值来更新i,更新完要继续维护这个斜率单调队列,若斜率(I,r)<斜率(r,r-1),则将r踢出队列,因为i一定比r优,最后的答案即为dp[n]

/**************************************************************

    Problem: 1010

    User: syh0313

    Language: C++

    Result: Accepted

    Time:144 ms

    Memory:22392 kb

****************************************************************/

 

#include <iostream>

#include <cstdio>

#include <cstdlib>

#include <cmath>

using namespace std;

const int maxn=50010;

int n,q[100*maxn],l,r;

long long k,a[maxn],sum[maxn],f[maxn],dp[maxn],c;

int main()

{

    scanf("%d%lld",&n,&k); c=k+1;

    for (int i=1;i<=n;i++) scanf("%lld",&a[i]);

    for (int i=1;i<=n;i++) sum[i]=sum[i-1]+a[i],f[i]=sum[i]+i;

    for (int i=1;i<=n;i++)

    {

        long long now=2ll*f[i]-2ll*c;

        while (l<r && dp[q[l+1]]+f[q[l+1]]*f[q[l+1]]-dp[q[l]]-f[q[l]]*f[q[l]]<=now*(f[q[l+1]]-f[q[l]])) l++;

        int lc=q[l];

        dp[i]=dp[lc]+(f[i]-f[lc]-c)*(f[i]-f[lc]-c);

        while (l<r && (dp[q[r]]+f[q[r]]*f[q[r]]-dp[q[r-1]]-f[q[r-1]]*f[q[r-1]])*(f[i]-f[q[r]])>(dp[i]+f[i]*f[i]-dp[q[r]]-f[q[r]]*f[q[r]])*(f[q[r]]-f[q[r-1]])) r--;

        q[++r]=i;

    }

    printf("%lld\n",dp[n]);

return 0;

}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值