一本通1610玩具装箱

1610:玩具装箱

时间限制: 1000 ms         内存限制: 524288 KB

【题目描述】

原题来自:HNOI 2008

P 教授要去看奥运,但是他舍不得他的玩具,于是他决定把所有的玩具运到北京。

他使用自己的压缩器进行压缩。这个压缩器可以将任意物品变成一维,再放到一种特殊的一维容器中。P 教授有编号为 1N 的 N 件玩具,玩具经过压缩后会变成一维,第 i 件件玩具压缩后长度为 Ci 。

为了方便整理,P 教授要求:

在一个一维容器中,玩具的编号是连续的;

如果一个一维容器中有多个玩具,那么两件玩具之间要加入一个单位长度的填充物。形式地说,如果要将 i 号玩具到 j 号玩具 (i≤j) 放到同一个容器中,则容器长度不小于x=ji+jk=iCk

制作容器的费用与容器的长度有关,根据教授研究,如果容器长度为 x,其制作费用为 (XL)2 ,其中 L是一个常量。

P 教授不关心容器的数目,他可以制作出任意长度的容器,甚至超过 L。试求最小费用。

【输入】

第一行输入两个整数 N,L;

接下来 N 行,每行一个整数 Ci 。

【输出】

输出最小费用。

【输入样例】

5 4
3
4
2
1
4

【输出样例】

1

【提示】

数据范围与提示:

对于全部数据,1≤N≤5×104,1≤L,Ci≤10

 

sol:这题关键是暴力要写的尽量简洁些,式子才好推。。。

考虑如何使转移尽量简洁,Qzh[i]=Cost(1~i),使得Costi+=i,但这样会使得每次多一个,怎么办,把L+1就好了

方程就简洁了 dp[i]=dp[j]+Sqr(Qzh[i]-Qzh[j]-L),这样就很好推了

推出 j<k<i时 (为简洁把Qzh称作S)

若 dp[k]+S[k]2-dp[j]-S[j]2<=(S[i]-L)*(2*(S[k]-S[j]))成立,则 k 比 j 优

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
inline ll read()
{
    ll s=0;
    bool f=0;
    char ch=' ';
    while(!isdigit(ch))
    {
        f|=(ch=='-'); ch=getchar();
    }
    while(isdigit(ch))
    {
        s=(s<<3)+(s<<1)+(ch^48); ch=getchar();
    }
    return (f)?(-s):(s);
}
#define R(x) x=read()
inline void write(ll x)
{
    if(x<0)
    {
        putchar('-'); x=-x;
    }
    if(x<10)
    {
        putchar(x+'0'); return;
    }
    write(x/10);
    putchar((x%10)+'0');
    return;
}
#define W(x) write(x),putchar(' ')
#define Wl(x) write(x),putchar('\n')
const int N=50005;
int n,L;
ll Qzh[N];
ll dp[N];
inline ll Sqr(ll x)
{
    return x*x;
}
int main()
{
    int i,j;
    R(n); L=read()+1;
    for(i=1;i<=n;i++)
    {
        Qzh[i]=Qzh[i-1]+read();
    }
    for(i=1;i<=n;i++)
    {
        Qzh[i]+=i;
    }
    memset(dp,63,sizeof dp); dp[0]=0;
    for(i=1;i<=n;i++)
    {
        for(j=0;j<i;j++)
        {
            dp[i]=min(dp[i],dp[j]+Sqr(Qzh[i]-Qzh[j]-L));
        }
    }
    Wl(dp[n]);
    return 0;
}
/*
input
5 4
3
4
2
1
4
output
1
*/
暴力代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
inline ll read()
{
    ll s=0;
    bool f=0;
    char ch=' ';
    while(!isdigit(ch))
    {
        f|=(ch=='-'); ch=getchar();
    }
    while(isdigit(ch))
    {
        s=(s<<3)+(s<<1)+(ch^48); ch=getchar();
    }
    return (f)?(-s):(s);
}
#define R(x) x=read()
inline void write(ll x)
{
    if(x<0)
    {
        putchar('-'); x=-x;
    }
    if(x<10)
    {
        putchar(x+'0'); return;
    }
    write(x/10);
    putchar((x%10)+'0');
    return;
}
#define W(x) write(x),putchar(' ')
#define Wl(x) write(x),putchar('\n')
const int N=50005;
int n,L;
ll Qzh[N];
ll dp[N];
int Que[N];
inline ll Sqr(ll x)
{
    return x*x;
}
inline bool Panduan(int j,int k,int i) // j<k<i
{
    ll S1=dp[k]+Sqr(Qzh[k])-dp[j]-Sqr(Qzh[j]);
    ll S2=2*(Qzh[i]-L)*(Qzh[k]-Qzh[j]);
    return (S1<=S2)?(1):(0);
}
inline bool Panduan_Rev(int j,int k,int i) //j<k<i
{
    ll S1=(dp[k]+Sqr(Qzh[k])-(dp[j]+Sqr(Qzh[j])))*(2*(Qzh[i]-Qzh[k]));
    ll S2=(dp[i]+Sqr(Qzh[i])-(dp[k]+Sqr(Qzh[k])))*(2*(Qzh[k]-Qzh[j]));
    return (S1>=S2)?(1):(0);
}
int main()
{
    int i,j;
    R(n); L=read()+1;
    for(i=1;i<=n;i++)
    {
        Qzh[i]=Qzh[i-1]+read();
    }
    for(i=1;i<=n;i++)
    {
        Qzh[i]+=i;
    }
    int Head=1,Tail=1; Que[1]=0;
    dp[0]=0;
    for(i=1;i<=n;i++)
    {
        while(Head<Tail&&Panduan(Que[Head],Que[Head+1],i)) Head++;
        int j=Que[Head];
        dp[i]=dp[j]+Sqr(Qzh[i]-Qzh[j]-L);
        while(Head<Tail&&Panduan_Rev(Que[Tail-1],Que[Tail],i)) Tail--;
        Que[++Tail]=i;
    }
    Wl(dp[n]);
    return 0;
}
/*
input
5 4
3
4
2
1
4
output
1
*/
斜率优化
posted @ 2019-02-20 22:39  yccdu  阅读(347)  评论(0编辑  收藏  举报