1010 玩具装箱toy
易得O(n^2)的dp,转移式为dp[i]=min{dp[j]+(i-j-1+sum[i]-sum[j]-L)^2},所以我们考虑用斜率来优化这个dp式子,设sum[i]为前缀和,f[i]=sum[i]+i,c=L+1,考虑j,k<i,当(dp[j]+f[j]^2-dp[k]-f[k]^2)/(f[j]-f[k])<=2*(f[i]-c)时j的答案比k优,因为f[i]-c单调增,可以可用单调队列维护单调增的斜率,对于每个i,当前队列首,若斜率(l+1,l)<2*(f[i]-c)则l+1肯定比l优,所以将l踢出队列,然后用q[l]的值来更新i,更新完要继续维护这个斜率单调队列,若斜率(I,r)<斜率(r,r-1),则将r踢出队列,因为i一定比r优,最后的答案即为dp[n]。
/**************************************************************
Problem: 1010
User: syh0313
Language: C++
Result: Accepted
Time:144 ms
Memory:22392 kb
****************************************************************/
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
using
namespace
std;
const
int
maxn=50010;
int
n,q[100*maxn],l,r;
long
long
k,a[maxn],sum[maxn],f[maxn],dp[maxn],c;
int
main()
{
scanf
(
"%d%lld"
,&n,&k); c=k+1;
for
(
int
i=1;i<=n;i++)
scanf
(
"%lld"
,&a[i]);
for
(
int
i=1;i<=n;i++) sum[i]=sum[i-1]+a[i],f[i]=sum[i]+i;
for
(
int
i=1;i<=n;i++)
{
long
long
now=2ll*f[i]-2ll*c;
while
(l<r && dp[q[l+1]]+f[q[l+1]]*f[q[l+1]]-dp[q[l]]-f[q[l]]*f[q[l]]<=now*(f[q[l+1]]-f[q[l]])) l++;
int
lc=q[l];
dp[i]=dp[lc]+(f[i]-f[lc]-c)*(f[i]-f[lc]-c);
while
(l<r && (dp[q[r]]+f[q[r]]*f[q[r]]-dp[q[r-1]]-f[q[r-1]]*f[q[r-1]])*(f[i]-f[q[r]])>(dp[i]+f[i]*f[i]-dp[q[r]]-f[q[r]]*f[q[r]])*(f[q[r]]-f[q[r-1]])) r--;
q[++r]=i;
}
printf
(
"%lld\n"
,dp[n]);
return
0;
}