1 条题解
-
0
设 表示前 个玩具的答案。则有转移:
$$dp(i)=\min_{0\leq j < i}\left[dp(j)+\left(\sum_{k=j+1}^ic_k+i-(j+1)-L\right)^2\right]. $$设 是 的前缀和,,则有 $dp(i)=\min\limits_{0\leq j < i}\left[dp(j)+(x_i-x_j-1-L)^2\right]$。
对于 ,若从 转移比 优秀,则有
$$dp(j_1)+(x_i-x_{j_1}-L-1)^2 \geq dp(j_2)+(x_i-x_{j_2}-L-1)^2. $$拆开可得 $\left[dp(j_2)+(x_{j_2}+L+1)^2\right]-\left[dp(j_1)+(x_{j_1}+L+1)^2\right] \leq 2x_i(x_{j_2}-x_{j_1})$。
记 ,则上式等价于 。
可以把 看作平面上的点,维护一个单调升的队列即可。
时间复杂度 。
/** * @date: 2024.04.06 * @problem: P3195, BZOJ1010 * @tags: 动态规划, 斜率优化 */ #include<bits/stdc++.h> using namespace std; int n,l; long long c[50001],x[50001],y[50001],dp[50001]; int q[50001],head,tail; inline double slope(int u,int v){ return (y[v]-y[u])*1.0/(x[v]-x[u]); } int main(){ scanf("%d%d",&n,&l); for(int i=1;i<=n;i++) scanf("%lld",c+i),c[i]+=c[i-1]; x[0]=0,y[0]=(l+1ll)*(l+1); for(int i=1;i<=n;i++){ x[i]=c[i]+i; while(head<tail&&slope(q[head],q[head+1])<=2*x[i])head++; dp[i]=dp[q[head]]+(x[i]-x[q[head]]-l-1)*(x[i]-x[q[head]]-l-1); y[i]=(x[i]+l+1)*(x[i]+l+1)+dp[i]; while(head<tail&&slope(q[tail],i)<slope(q[tail-1],q[tail]))tail--; q[++tail]=i; } printf("%lld\n",dp[n]); return 0; }
- 1
信息
- ID
- 2131
- 时间
- 1000ms
- 内存
- 125MiB
- 难度
- 6
- 标签
- 递交数
- 11
- 已通过
- 5
- 上传者