HYSBZ/BZOJ 1010 [HNOI2008] 玩具装箱 - dp&斜率优化
分析:
题目一看就是dp题。
dp[i] :前i个玩具所需的最小cost
sum[i] :c[i]的前缀和
复杂度O(
由于牵扯到sum[j-1],而不是sum[j],将方程改写为:
为了方便表示,记:
f[i] = sum[i] + i , c=1+L
则:
——————————————————————————————————————————
STEP 1:证明较优状态决策点对后续状态的持续影响 (就是说:对于当前状态i,有决策点k优于j,那么必定的,对于i之后的某个状态T,仍有决策点k优于j)
假设对于当前状态i,有决策点k优于j ,j < k
则:
又因为f(x)是递增的,设
要证:
要证:
要证:
要证:
有结合f(x)的单调递增性,即可证明。
——————————————————————————————————————————
STEP 2:找斜率方程
由 (此时k优于j)
推得:
记
则:
——————————————————————————————————————————
Solution:
分析了那么久,累死了。
斜率优化用一个队列维护。
维护原则看代码吧,提示:que[]中的pos按大小顺序排。
——————————————————————————————————————————
#include<cstdio>
#define MAXN 50000
typedef long long LL;
int n,c,L;
LL sum[MAXN+10],f[MAXN+10],dp[MAXN+10],que[MAXN+10];
void read()
{
int x;
scanf("%d%d",&n,&L);
for(int i=1;i<=n;i++){
scanf("%d",&x);
sum[i]=sum[i-1]+x;
}
for(int i=1;i<=n;i++)
f[i]=sum[i]+i;
c=L+1;
}
LL G(int k,int j){
return (dp[k]+(f[k]+c)*(f[k]+c)) - (dp[j]+(f[j]+c)*(f[j]+c));
}
LL S(int k,int j){
return 2*(f[k]-f[j]);
}
void DP()
{
int front=0,rear=1,now;//que[0]=0,以便算出f[1]
for(int i=1;i<=n;i++){
while(front<rear-1){
if(G(que[front+1],que[front])<=S(que[front+1],que[front])*f[i])
front++;
else
break;
}
now=que[front];
dp[i]=dp[now]+(f[i]-f[now]-c)*(f[i]-f[now]-c);
while(front<rear-1){
if(G(i,que[rear-1])*S(que[rear-1],que[rear-2])<=G(que[rear-1],que[rear-2])*S(i,que[rear-1]))
rear--;
else
break;
}
que[rear++]=i;
}
}
int main()
{
read();
DP();
printf("%I64d\n",dp[n]);
}