BZOJ1010 [HNOI2008]玩具装箱

Description

  P教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京。他使用自己的压缩器进行压
缩,其可以将任意物品变成一堆,再放到一种特殊的一维容器中。P教授有编号为1...N的N件玩具,第i件玩具经过
压缩后变成一维长度为Ci.为了方便整理,P教授要求在一个一维容器中的玩具编号是连续的。同时如果一个一维容
器中有多个玩具,那么两件玩具之间要加入一个单位长度的填充物,形式地说如果将第i件玩具到第j个玩具放到一
个容器中,那么容器的长度将为 x=j-i+Sigma(Ck) i<=K<=j 制作容器的费用与容器的长度有关,根据教授研究,
如果容器长度为x,其制作费用为(X-L)^2.其中L是一个常量。P教授不关心容器的数目,他可以制作出任意长度的容
器,甚至超过L。但他希望费用最小.

Input

  第一行输入两个整数N,L.接下来N行输入Ci.1<=N<=50000,1<=L,Ci<=10^7

Output

  输出最小费用

Sample Input

5 4
3
4
2
1
4

Sample Output

1
 
正解:斜率优化dp
 
解题报告:我还是太弱了,斜率优化都快忘记了,还是赶紧来复习一下吧
 
#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#define ll long long
#define ld long double
#define RG register
const int N = 100000;

using namespace std;

int gi(){
    char ch=getchar();int x=0;
    while(ch<'0' || ch>'9') ch=getchar();
    while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
    return x;
}

int f[N],c,head,tail,stack[N];
ll s[N],dp[N];

ld cmp(int x,int y){
    return (ld)(s[y]*s[y]+2*s[y]*c+dp[y]-s[x]*s[x]-2*s[x]*c-dp[x])*1.0/(2.0*(ld)(s[y]-s[x]));
}

int main(){
    freopen("toy.in","r",stdin);
    freopen("toy.out","w",stdout);
    int n=gi(),l=gi();
    c=l+1;
    for (RG int i=1; i<=n; ++i) f[i]=gi(),s[i]=s[i-1]+f[i];
    for (RG int i=1; i<=n; ++i) s[i]+=i;
    for (RG int i=1; i<=n; ++i){
        while(head<tail && cmp(stack[head],stack[head+1])<=s[i]) ++head;
        dp[i]=dp[stack[head]]+(s[i]-s[stack[head]]-c)*(s[i]-s[stack[head]]-c);
        while(head<tail && cmp(stack[tail],i)<cmp(stack[tail-1],stack[tail])) --tail;
        stack[++tail]=i;
    }
    printf("%lld\n",dp[n]);
    return 0;
}

 

 --------------------------------------------------

1d1d好像也可以过

 

#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#define RG register
#define ll long long
#define File(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout)
const int N = 100000;
 
using namespace std;
 
int gi(){
    char ch=getchar();int x=0;
    while(ch<'0' || ch>'9') ch=getchar();
    while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
    return x;
}
 
ll f[N],dp[N];
int n,s,head,tail;
 
struct date{
    int l,r,p;
}stack[N];
 
ll cal(int i,int v){
    return dp[v]+(f[i]-f[v]+i-v-s)*(f[i]-f[v]+i-v-s);
}
 
int find(int l,int r,int i,int p){
    int z=1,y=r,ans=r+1,mid;
    while(z<=y){
        mid=(z+y)>>1;
        if (cal(mid,i)<cal(mid,p)) ans=mid,y=mid-1;
        else z=mid+1;
    }
    return ans;
}
 
int main(){
    n=gi(),s=gi()+1,head=1,tail=1;
    for (RG int i=1; i<=n; ++i) f[i]=f[i-1]+gi();
    stack[1]=(date){1,n,0};
    for (RG int i=1; i<=n; ++i){
        while(stack[head].r<i) ++head;
        dp[i]=cal(i,stack[head].p);
        int y=stack[tail].r;
        while(tail>head && stack[tail].l>i && cal(stack[tail].l,i)<cal(stack[tail].l,stack[tail].p)) --tail;
        if (head<=tail){
            int t=find(stack[tail].l,stack[tail].r,i,stack[tail].p);
            if (t<=y){
                stack[tail].r=t-1;
                stack[++tail]=(date){t,y,i};
            }
        }
    }
    printf("%lld\n",dp[n]);
}

 

posted @ 2017-03-06 16:17  Cjk_2001  阅读(184)  评论(1编辑  收藏  举报