分析:
题目一看就是dp题。
dp[i] :前i个玩具所需的最小cost
sum[i] :c[i]的前缀和
dp[i]=min{dp[j]+(sum[i]−sum[j−1]+i−j−L)2,1<=j<=i}
复杂度O( n2 ),肯定要优化
由于牵扯到sum[j-1],而不是sum[j],将方程改写为:
dp[i]=min{dp[j]+(sum[i]−sum[j]+i−(j+1)−L)2},0<=j<i
为了方便表示,记:
f[i] = sum[i] + i , c=1+L
则:
dp[i]=min{dp[j]+(f[i]−f[j]−c)2},0<=j<i
——————————————————————————————————————————
STEP 1:证明较优状态决策点对后续状态的持续影响 (就是说:对于当前状态i,有决策点k优于j,那么必定的,对于i之后的某个状态T,仍有决策点k优于j)
假设对于当前状态i,有决策点k优于j ,j < k
则:
dp[k]+(f[i]−f[k]−c)2<=dp[j]+(f[i]−f[j]−c)2
又因为f(x)是递增的,设 f[T]=f[i]+t
要证:
dp[k]+(f[T]−f[k]−c)2<=dp[j]+(f[T]−f[j]−c)2
要证:
dp[k]+(f[i]+t−f[k]−c)2<=dp[j]+(f[i]+t−f[j]−c)2
要证:
dp[k]+(f[i]−f[k]−c)2+2t(f[i]−f[k]−c)+t2<=dp[j]+(f[i]−f[j]−c)2+2t(f[i]−f[j]−c)+t2
要证:
2t(f[i]−f[k]−c)<=2t(f[i]−f[j]−c)
有结合f(x)的单调递增性,即可证明。
——————————————————————————————————————————
STEP 2:找斜率方程
由 (此时k优于j)
dp[k]+(f[i]−f[k]−c)2<=dp[j]+(f[i]−f[j]−c)2
推得:
dp[k]+(f[k]+c)2−(dp[j]+(f[j]+c)2)<=2(f[k]−f[j])∗f[i]
记
G(k,j)=dp[k]+(f[k]+c)2−(dp[j]+(f[j]+c)2)
S(k,j)=2(f[k]−f[j])
则:
K(k,j)=G(k,j)S(k,j)<=f[i]
——————————————————————————————————————————
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]);
}