洛谷P4072 [SDOI2016]征途(带权二分,斜率优化)

洛谷题目传送门

一开始肯定要把题目要求的式子给写出来

我们知道方差的公式s2=i=1m(xix¯)2m

题目要乘m2再输出,于是

m2s2=mi=1m(xix¯)2

=m(i=1mxi22x¯i=1mxi+mx¯2)

=mi=1mxi2(i=1mxi)2

于是只要最小化i=1mxi2即可。

然而选m段非常不好办。这时候可以联想到凸优化。设Gm表示选mi=1mxi2的最小值,当m增大的时候Gm显然会减小,凭蒟蒻的感性理解,多分出一段对答案的影响幅度也越来越小,也就是说Gx关于x的函数图像大概是下凸的。

我们用一个斜率为mid的直线去切这个凸包。显然mid的下界取[0,1]之间的斜率,是总路程平方级别的,上界是0。因为切线在凸包的下方,所以多选一段的代价不是+mid而是mid

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

接下来就是斜率优化的过程。设fi为前i条路的最优答案,xi为路程长度的前缀和,写出转移方程

fi=minj=0i{fj2xixj+xj2}+xi2

决策j优于k当且仅当

fj2xixj+xj2<fk2xixk+xk2

fj+xj2fkxk2xjxk<2xi

于是设yi=fi+xi2,把决策看成点(xi,yi),使用单调队列就OK了。注意这里要记ci表示最优决策下将前i条路分出的段数。最后判断cnm的关系来调整斜率。

由于这一题的斜率肯定不会有小数,故也不必担心二分中的一些边界问题。

#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 @   Flash_Hu  阅读(697)  评论(0编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示
剑桥
17:14发布
剑桥
17:14发布
5°
西风
7级
空气质量
相对湿度
34%
今天
多云
-3°/5°
周六
-1°/3°
周日
-2°/7°