# 洛谷P4072 [SDOI2016]征途（带权二分，斜率优化）

$$m^2s^2=m\sum\limits_{i=1}^{m}(x_i-\overline x)^2$$

$$=m(\sum\limits_{i=1}^{m}x_i^2-2\overline{x}\sum\limits_{i=1}^{m}x_i+m\overline{x}^2)$$

$$=m\sum\limits_{i=1}^{m}x_i^2-(\sum\limits_{i=1}^{m}x_i)^2$$

update:蒟蒻弃用了用直线切凸包的理解方法，蒟蒻用导数思想理解DP凸优化的思路可以看这里

$$f_i=\min\limits_{j=0}^{i}\{f_j-2x_ix_j+x_j^2\}+x_i^2$$

$$f_j-2x_ix_j+x_j^2<f_k-2x_ix_k+x_k^2$$

$$\frac{f_j+x_j^2-f_k-x_k^2}{x_j-x_k}<2x_i$$

#include<cstdio>
#define RG register
#define R RG int
#define G c=getchar()
#define Calc(j,k) (y[j]-y[k])/(x[j]-x[k])
typedef long long LL;
const int N=3009;
int n,q[N],c[N];
double f[N],k[N],x[N],y[N];
inline int in(){
RG char G;
while(c<'-')G;
R x=c&15;G;
while(c>'-')x=x*10+(c&15),G;
return x;
}
inline double sqr(RG double x){
return x*x;
}
inline void work(R mid){//斜率优化
R h,t,i;
for(h=t=i=1;i<=n;++i){
while(h<t&&k[h]<2*x[i])++h;
f[i]=f[q[h]]+sqr(x[i]-x[q[h]])-mid;//每转移一次要减一下mid
y[i]=f[i]+sqr(x[i]);
c[i]=c[q[h]]+1;//记录段数
while(h<t&&k[t-1]>Calc(q[t],i))--t;
k[t]=Calc(q[t],i);q[++t]=i;
}
}
int main(){
n=in();R m=in(),l,r,mid,i;
for(i=1;i<=n;++i)x[i]=x[i-1]+in();
l=-sqr(x[n]);r=0;//大致确定下界
while(l<r){
work(mid=(l+r+1)/2);//注意负数的下取整问题
c[n]<=m?l=mid:r=mid-1;
}
work(l);
printf("%.0lf\n",m*(f[n]+m*l)-sqr(x[n]));//先加回m*l
return 0;
}

posted @ 2018-08-27 22:58  Flash_Hu  阅读(653)  评论(0编辑  收藏  举报