【斜率dp】bzoj1010 玩具装箱toy

来源:互联网 发布:手机搞笑视频软件 编辑:程序博客网 时间:2024/04/28 16:44

http://www.lydsy.com/JudgeOnline/problem.php?id=1010

//#pragma comment(linker, "/STACK:102400000,102400000")#include <stdio.h>#include <string.h>#include <iostream>#include <algorithm>#include <vector>#include <queue>#include <stack>#include <set>#include <map>#include <string>#include <math.h>#include <stdlib.h>#include <time.h>using namespace std;typedef long long LL;const int INF = 0x3f3f3f3f;/*给定N个物品,可以划分为若干个组,每个组的物品位置必须连续,其代价是:如放第i个物品到第j个物品,代价为(j-i+sum(c[i]->c[j])-L)^2求最小代价。pre[i] 为前缀和朴素转移方程:dp[i]=dp[j]+(i-j-1+pre[i]-pre[j]-L)^2;简化式子:f[i]=pre[i]+i; C=L+1;那么dp[i]=dp[j]+(f[i]-f[j]-C)^2;首先要证明决策单调性,才能保证被单调队列单调性pop掉的决策对后面dp无影响。解释下决策单调是什么应该就能理解,决策单调,对于dp[i]和dp[t](t>i),如果dp[i]的最优决策是k,那么dp[t]的最优决策一定是大于等于k的。以下请结合上面定义理解:决策单调性证明:首先假设j,k为dp[i]的两个决策,并且(j<k)那么:dp[j]+(f[i]-f[j]-C)^2 >= dp[k]+(f[i]-f[k]-C)^2 [1]假设:f[t]=f[i]+v(v>0, t>i[t在i后面])现在要证明决策单调性就是要证:dp[j]+(f[t]-f[j]-C)^2(dp[t]的决策j) >= dp[k]+(f[t]-f[k]-C)^2(dp[t]的决策k)dp[j]+(f[i]+v-f[j]-C)^2 >= dp[k]+(f[i]+v-f[j]-C)^2dp[j]+(f[i]-f[j]-C)^2+2*v*(f[i]-f[j]-C)+v^2 >= dp[k]+(f[i]-f[k]-C)^2+2*v*(f[i]-f[k]-C)+v^2因为[1]: 证明 f[i]-f[j]-C >= f[i]-f[k]-C  即可因为显然 f[j] > f[k],所以存在决策单调性。因为dp[k]+(f[i]-f[k]-c)^2<=dp[j]+(f[i]-f[j]-c)^2展开 dp[k]+f[i]^2-2*f[i]*(f[k]+c)+(f[k]+c)^2<=dp[j]+f[i]^2-2*f[i]*(f[j]+c)+(f[j]+c)^2即 dp[k]-2*f[i]*(f[k]+c)+(f[k]+c)^2<=dp[j]-2*f[i]*(f[j]+c)+(f[j]+c)^2即 (dp[k]+(f[k]+c)^2-dp[j]-(f[j]+c)^2)/2*(f[k]-f[j])<=f[i]斜率xie(j,k):(dp[k]+(f[k]+c)^2-dp[j]-(f[j]+c)^2)/2*(f[k]-f[j])单调队列要维护最优决策当xie(q[l],q[l+1])<=f[i],pop队首。因为f[i]是单调递增的,单调队列要维护一个下凸壳。当xie(q[r-1],q[r])<=xie(q[r],i),pop队尾*/const int N = 50010;int q[N],n;LL a[N],pre[N],f[N],dp[N],L,C;double xie(int j,int k){    return ((dp[k]+(f[k]+C)*(f[k]+C)-dp[j]-(f[j]+C)*(f[j]+C)))/(2.0*(f[k]-f[j]));}int main(){    scanf("%d%lld",&n,&L);    C = L+1;    pre[0] = 0;    for(int i=1; i<=n; i++){        scanf("%lld",&a[i]);        pre[i] = pre[i-1]+a[i];        f[i] = pre[i]+(LL)i;    }    int l=1, r=0;    q[++r]=0, dp[0]=0;    for(int i=1; i<=n; i++){        while(l<r && xie(q[l],q[l+1])<=f[i]) l++;        int j = q[l];        dp[i] = dp[j]+(f[i]-f[j]-C)*(f[i]-f[j]-C);        while(l<r && xie(q[r-1],q[r])>xie(q[r],i)) r--;        q[++r] = i;    }    printf("%lld\n",dp[n]);    return 0;}


原创粉丝点击