P4983 忘情

这题真的很裸吧,就是一个更为简单的( ext{wqs})二分然后斜率优化。

题目里的式子稍加推导发现就是((sum+1)^2),斜率优化即可。

注意这里斜率比较不能用乘法,因为会爆( ext{long long}),然后二分的边界要开大一点。

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=2e5+10;
const int mod=1e9+7;
int n,m,a[maxn],sum[maxn],f[maxn],num[maxn],q[maxn];
inline int read(){
	int x=0,f=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
	return x*f;
}
inline int yval(int x){return f[x]+sum[x]*sum[x]-2*sum[x];}
inline int dx(int x,int y){return sum[y]-sum[x];}
inline int dy(int x,int y){return yval(y)-yval(x);}
inline double slope(int x,int y){return 1.0*dy(x,y)/dx(x,y);}
inline void calc(int val){
	int l,r;q[l=r=1]=0;
	for(int i=1;i<=n;i++){
		while(l<r&&slope(q[l],q[l+1])<=2*sum[i])l++;
		f[i]=f[q[l]]+(sum[i]-sum[q[l]]+1)*(sum[i]-sum[q[l]]+1)+val;
		num[i]=num[q[l]]+1;
		while(l<r&&slope(q[r],i)<=slope(q[r-1],q[r]))r--;
		q[++r]=i;
	}
}
signed main(){
	n=read(),m=read();
	for(int i=1;i<=n;i++)a[i]=read();
	for(int i=1;i<=n;i++)sum[i]=sum[i-1]+a[i];
	int l=0,r=1e18;
	for(int i=1;i<=100;i++){
		int mid=(l+r)>>1;
		calc(mid);
		if(num[n]>m)l=mid;
		else r=mid;
	}
	calc(l);
	printf("%lld
",f[n]-l*m);
	return 0;
}
原文地址:https://www.cnblogs.com/syzf2222/p/14411763.html