#斜率优化,动态规划#bzoj 1010 洛谷 3195 玩具装箱TOY

洛谷题目链接
bzoj题目链接


分析

根据题目,我们可以写出朴素的状态转移方程
d p [ i ] = m i n { d p [ j ] + ( j − i − 1 + ∑ k = j i c [ k ] − L ) 2 } dp[i]=min\{dp[j]+(j-i-1+\sum_{k=j}^ic[k]-L)^2\} dp[i]=min{dp[j]+(ji1+k=jic[k]L)2}
预处理 c c c的前缀和 s u m sum sum,并使 s u m [ i ] 加 上 i sum[i]加上i sum[i]i
那么原方程可变为 d p [ i ] = m i n { d p [ j ] + ( ( s u m [ i ] − s u m [ j ] ) − ( L + 1 ) ) 2 } dp[i]=min\{dp[j]+((sum[i]-sum[j])-(L+1))^2\} dp[i]=min{dp[j]+((sum[i]sum[j])(L+1))2}
k ( j &lt; k ) k(j&lt;k) k(j<k) j j j决策更优,那么
d p [ k ] + ( ( s u m [ i ] − s u m [ k ] ) − ( L + 1 ) ) 2 ≤ d p [ j ] + ( ( s u m [ i ] − s u m [ j ] ) − ( L + 1 ) ) 2 dp[k]+((sum[i]-sum[k])-(L+1))^2\leq dp[j]+((sum[i]-sum[j])-(L+1))^2 dp[k]+((sum[i]sum[k])(L+1))2dp[j]+((sum[i]sum[j])(L+1))2
初步化简得到
d p [ k ] + a [ k ] 2 − 2 a [ i ] a [ k ] + ( 2 L + 2 ) a [ k ] ≤ d p [ j ] + a [ j ] 2 − 2 a [ i ] a [ j ] + ( 2 L + 2 ) a [ j ] dp[k]+a[k]^2-2a[i]a[k]+(2L+2)a[k]\leq dp[j]+a[j]^2-2a[i]a[j]+(2L+2)a[j] dp[k]+a[k]22a[i]a[k]+(2L+2)a[k]dp[j]+a[j]22a[i]a[j]+(2L+2)a[j]
合并得到 d p [ k ] − d p [ j ] + a [ k ] 2 − a [ j ] 2 + ( 2 L + 2 ) ( a [ k ] − a [ j ] ) ≤ 2 a [ i ] ( a [ k ] − a [ j ] ) dp[k]-dp[j]+a[k]^2-a[j]^2+(2L+2)(a[k]-a[j])\leq 2a[i](a[k]-a[j]) dp[k]dp[j]+a[k]2a[j]2+(2L+2)(a[k]a[j])2a[i](a[k]a[j])
然后就可以清晰地得到
d p [ k ] − d p [ j ] + a [ k ] 2 − a [ j ] 2 + ( 2 L + 2 ) ( a [ k ] − a [ j ] ) a [ k ] − a [ j ] ≤ 2 a [ i ] \frac{dp[k]-dp[j]+a[k]^2-a[j]^2+(2L+2)(a[k]-a[j])}{a[k]-a[j]}\leq 2a[i] a[k]a[j]dp[k]dp[j]+a[k]2a[j]2+(2L+2)(a[k]a[j])2a[i]
然而还可以进一步化简得到
d p [ k ] − d p [ j ] + a [ k ] + a [ j ] a [ k ] − a [ j ] ≤ 2 ( a [ i ] − L − 1 ) \frac{dp[k]-dp[j]+a[k]+a[j]}{a[k]-a[j]}\leq 2(a[i]-L-1) a[k]a[j]dp[k]dp[j]+a[k]+a[j]2(a[i]L1)
右边的已知值是单调递增的,所以维护下凸壳,于是


代码

#include <cstdio>
#include <cctype>
#define rr register
#define w(x) ((x)*(x))
using namespace std;
int head=1,tail=1,n,t,q[50001];
long long sum[50001],dp[50001];
inline signed iut(){
    rr int ans=0; rr char c=getchar();
    while (!isdigit(c)) c=getchar();
    while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
    return ans;
}
inline double slope(int x,int y){//计算斜率
    if (sum[y]-sum[x]==0) return 1e18;
    else return 1.0*(dp[y]-dp[x])/(sum[y]-sum[x])+sum[x]+sum[y];
}
signed main(){
    n=iut(); t=iut()+1;
    for (rr int i=1;i<=n;++i) sum[i]=sum[i-1]+iut();
    for (rr int i=1;i<=n;++i) sum[i]+=i;
    for (rr int i=1;i<=n;++i){
        while (head<tail&&slope(q[head],q[head+1])<=(sum[i]-t)<<1) ++head;//维护队头
        dp[i]=dp[q[head]]+w(sum[i]-sum[q[head]]-t);//dp方程
        while (head<tail&&slope(q[tail-1],q[tail])>slope(q[tail],i)) --tail;//维护队尾
        q[++tail]=i;
    }
    return !printf("%lld",dp[n]);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值