您的位置:首页 > 其它

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

2017-05-14 17:38 323 查看

累加器传送门:

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<iostream>
#include<cstdio>
#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(head<tail&&gety(q[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(head<tail&&(gety(i)-gety(q[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
);
return 0;
}




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



我交了几次,最开始交的已经pending了1h了

多半是评测机睡着了

P.S:本来我的代码多简洁的,设了getx()函数,gety()函数,getb()函数,getk()函数,很多东西可以缩的,然而我已经调到不相信人生了,全部都老老实实改成了现在这个样子
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: