dp斜率优化 bzoj 1010玩具装箱题解

累加器传送门:

http://blog.csdn.net/NOIAu/article/details/71775000

题目传送门:

https://cn.vjudge.net/problem/HYSBZ-1010


想哭啊,这道题写和调一共用了两个多小时,最后才发现死在了一个括号匹配上面,WA的一下就哭出来了,这个故事告诉我们查错的时候一定要检查括号匹配啊,有些是编译器看不出来的,现在心情还久久不能平静


首先进行分析
很容易写出一个dp转移方程

dp[i]=min(dp[j]+(i-j-1+cnt[i]-cnt[j]-L)^2);

注意到可以把括号里的

(i-j-1+cnt[i]-cnt[j]-L)

拆分成

((i-1+cnt[i]-L)+(-j-cnt[j]))


用完全平方公式可以得到

dp[i]=min(dp[j]+(i-1+cnt[i]-L)^2+2*(i-1+cnt[i]-L) *(-j-cnt[j])+(j+cnt[j])^2)

扔掉(i-1+cnt[i]-L)^2
得到

dp[i]=dp[j]+(j+cnt[j])^2-2*(i-1+cnt[i]-L)*(j+cnt[j])

b=dp[i]

y=dp[j]+(j+cnt[j])^2

k=2*(i-1+cnt[i]+L)^2

x=j+cnt[j]

b=y-kx

=> y=kx+b

其中x和y均满足单调性,所以维护点集(x,y)就行了,维护凸包即可
用斜率优化做就行了
斜率优化讲解:
http://blog.csdn.net/NOIAu/article/details/71774994


#include
#include 
#define MAXN 500000+10 
using namespace std;

int q[MAXN];
int head,tail;
int N,L;
long long temp;
long long cnt[MAXN],dp[MAXN];

long long getx(int i){ return i+cnt[i]; }  
long long gety(int i){ return dp[i]+(i+cnt[i])*(i+cnt[i]); }

int main(){
    scanf("%d%d",&N,&L); q[tail]=0;
    for(int i=1;i<=N;i++) scanf("%lld",cnt+i),cnt[i]+=cnt[i-1];
    for(int i=1;i<=N;i++){  
        long long k=2*(i-1-L+cnt[i]);
        while(headq[head+1])-k*getx(q[head+1])<=gety(q[head])-k*getx(q[head])) ++head;
        dp[i]=gety(q[head])-k*getx(q[head])+k*k/4;
        while(headq[tail-1]))*(getx(i)-getx(q[tail]))>=(gety(i)-gety(q[tail]))*(getx(i)-getx(q[tail-1]))) --tail;      
        q[++tail]=i;
    }
    printf("%lld\n",dp[N]);
    return 0;
} 

这里写图片描述

不要问我为什么这次没用vj测题

这里写图片描述

我交了几次,最开始交的已经pending了1h了
多半是评测机睡着了


P.S:本来我的代码多简洁的,设了getx()函数,gety()函数,getb()函数,getk()函数,很多东西可以缩的,然而我已经调到不相信人生了,全部都老老实实改成了现在这个样子


你可能感兴趣的:(动态规划)