[HNOI2008]玩具装箱TOY

91 篇文章 1 订阅
9 篇文章 0 订阅

参考MashiroSky大佬的Blog

题目描述:

给定N个物品,可以连续的划分为若干个组,每个组的代价是(物品数-1+每个物品单独的代价-L)^2,求最小代价.

题目分析:

先写出DP方程:

DP[i]=min(DP[j]+(sum[i]sum[j]+ij1+L)2)(j<i) D P [ i ] = m i n ( D P [ j ] + ( s u m [ i ] − s u m [ j ] + i − j − 1 + L ) 2 ) ( j < i )
这样的转移为 n2 n 2 数据范围为 5 万 ,很明显不行.
现在化简上面的DP方程
f[i]=sum[i]+iC=L1 f [ i ] = s u m [ i ] + i C = L − 1
DP[i]=min(DP[j]+(f[i]f[j]+C)2)(j<i) D P [ i ] = m i n ( D P [ j ] + ( f [ i ] − f [ j ] + C ) 2 ) ( j < i )

证明决策单调性:

假设 i 有两个决策点 j k (j < k)且 k 比 j 优
DP[j]+(f[i]f[j]+C)2>DP[k]+(f[i]f[k]+C)2 D P [ j ] + ( f [ i ] − f [ j ] + C ) 2 > D P [ k ] + ( f [ i ] − f [ k ] + C ) 2 设为 1 式
这里写图片描述

题目链接:

Luogu

Ac 代码:

#include <cstdio>
#include <iostream>
#define ll long long
const int maxn=50010;
int n,L;
ll a[maxn],f[maxn],s[maxn],dp[maxn],q[maxn];
double slope(ll x,ll y) 
{
    return (dp[x]-dp[y]+(f[x]+L)*(f[x]+L)-(f[y]+L)*(f[y]+L))/(2.0*(f[x]-f[y]));
}
int main()
{
    scanf("%d%d",&n,&L);
    L++;
    for(int i=1;i<=n;i++) scanf("%d",&s[i]),s[i]+=s[i-1];
    for(int i=1;i<=n;i++) f[i]=s[i]+i;
    int l=1,r=1;dp[1]=0;
    for (int i=1;i<=n;i++) 
    {
        while(l<r&&slope(q[l],q[l+1])<=f[i]) l++;//判断优劣 
        dp[i]=dp[q[l]]+(f[i]-f[q[l]]-L)*(f[i]-f[q[l]]-L);//队首最优 
        while(l<r&&slope(q[r-1],q[r])>slope(q[r],i)) r--;//维护下凸 
        q[++r]=i;
    }
    return printf("%lld",dp[n])*0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值