题目
预处理\(C\)的前缀和\(sum\)。设前\(i\)个物品的最小答案为\(f\)
\(f_i=\max\limits_{j\in[1,i)}(f_j+(sum_i-sum_j-L)^2)\)
拆开就是\(f_i=\max\limits_{j\in[1,i)}(f_j+sum_i^2+sum_j^2+L^2-2Lsum_i-2Lsum_j-2sum_isum_j)\)
稍微整理一下\(f_i=\max\limits_{j\in[1,i)}(f_j+sum_j^2-2Lsum_j-2sum_isum_j)+sum_i^2+L^2-2Lsum_i\)
然后直接斜率优化。
代码是以前写的,建议斜率交叉相乘后判断大小避免精度误差。

#include<bits/stdc++.h>
#define N 50001
using namespace std;
inline int read()
{
    int x=0;
    char ch=getchar();
    while(ch<'0'||ch>'9')
        ch=getchar();
    while(ch>='0'&&ch<='9')
        x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
    return x;
}
inline int max(int a,int b)
{
	return a>b? a:b;
}
long long sum[N],f[N],q[N],L;
inline double slope(int i,int j)
{
	return (double)(f[i]-f[j]+(sum[i]-sum[j])*(sum[i]+sum[j]+(L<<1)))/(double)(sum[i]-sum[j]);
}
int main()
{
	register int n=read();
	L=read()+1;
	for(register int i=1;i<=n;++i)
		sum[i]=sum[i-1]+read()+1;
	register int hd=1,tl=1;
	for(register int i=1;i<=n;++i)
	{
		while(hd<tl&&slope(q[hd],q[hd+1])<2*sum[i])
			++hd;
		f[i]=f[q[hd]]+(sum[i]-sum[q[hd]]-L)*(sum[i]-sum[q[hd]]-L);
        while(hd<tl&&slope(i,q[tl-1])<slope(q[tl-1],q[tl]))
			--tl;
        q[++tl]=i;
    }
    return printf("%lld",f[n]),0;
}

相关文章:

  • 2021-11-17
  • 2022-12-23
  • 2021-06-14
  • 2021-04-08
  • 2021-06-22
  • 2021-07-01
  • 2021-12-03
猜你喜欢
  • 2021-09-15
  • 2021-11-04
  • 2022-12-23
  • 2022-01-19
  • 2021-10-10
  • 2021-09-20
  • 2021-05-28
相关资源
相似解决方案