[HNOI2008]玩具装箱
试题分析
设$dp[i]$表示为去选择第$i$个位最后一个的总价值。复杂度:$O(n^2)$
将$s[i]=\sum_{i=1}^i {c[i]}$,然后$a_i=s_i+i,b_i=s_i+i+1+L$,所以$dp[i]=min{dp[j]+(a[i]-b[j])^2}$
得:$f[j]+b[j]^2=2\times a[i]\times b[j]+f[i]-a[i]^2$
发现$f[j]+b[j]^2$设为$Y$,$2\times a[i]$为斜率,$b[j]$设为$X$,我们发现要求截距最短,即为下凸壳。然后就可以斜率优化了
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<climits> #define int long long using namespace std; inline int read(){ int f=1,ans=0;char c=getchar(); while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();} return f*ans; } const int N=50001; int Y[N],X[N]; int f[N],s[N],n,L,a[N],b[N],l,r,que[N]; signed main(){ memset(f,127/3,sizeof(f)); n=read(),L=read(); for(int i=1;i<=n;i++) s[i]=s[i-1]+read(); for(int i=0;i<=n;i++) a[i]=s[i]+i,b[i]=s[i]+i+1+L; l=1,r=1,que[1]=0,f[0]=0;Y[0]=f[0]+b[0]*b[0],X[0]=b[0]; for(int i=1;i<=n;i++){ while(l<r&&Y[que[l+1]]-Y[que[l]]<=2*a[i]*(X[que[l+1]]-X[que[l]])) l++; f[i]=f[que[l]]+(a[i]-b[que[l]])*(a[i]-b[que[l]]); X[i]=b[i],Y[i]=f[i]+b[i]*b[i]; while(l<r&&(Y[que[r]]-Y[que[r-1]])*(X[i]-X[que[r]])>=(X[que[r]]-X[que[r-1]])*(Y[i]-Y[que[r]])) r--; que[++r]=i; }cout<<f[n]; }