【bzoj4518】 Sdoi2016—征途

http://www.lydsy.com/JudgeOnline/problem.php?id=4518 (题目链接)

题意

  给出n个连续的整数,求将它们分成m段,求最小方差*m^2。

Solution

  把m^2乘进去,然后就约掉了一大堆东西,我们用${f_{i,j}}$表示前j个数分成i组的最小值:

$${f_{i,j}=Min\{f_{i-1,k}+(S_i-S_k)^2\}}$$

  显然这可以斜率优化。然后就斜率优化咯。

细节

  最近很不爽,头晕炸了。。一道sb题写了2个小时。。。我真是zz

代码

// bzoj4518
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
#define LL long long
#define inf 1<<30
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
using namespace std;

const int maxn=3010;
int q[maxn],n,m,p;
LL s[maxn],f[2][maxn];

double slope(int i,int j) {
	return (double)(f[p^1][i]+m*s[i]*s[i]-f[p^1][j]-m*s[j]*s[j])/(s[i]-s[j]);
}
int main() {
	scanf("%d%d",&n,&m);
	for (int x,i=1;i<=n;i++) scanf("%d",&x),s[i]=s[i-1]+x;
	for (int i=1;i<=n;i++) f[0][i]=m*s[i]*s[i];
	for (int j=2;j<=m;j++) {
		int l=1,r=0;p^=1;
		for (int i=j-1;i<j;i++) q[++r]=i;
		for (int i=j;i<=n;i++) {
			while (l<r && slope(q[l],q[l+1])<=2*m*s[i]) l++;
			f[p][i]=f[p^1][q[l]]+m*(s[i]-s[q[l]])*(s[i]-s[q[l]]);
			while (l<r && slope(q[r-1],q[r])>slope(q[r],i)) r--;
			q[++r]=i;
		}
	}
	printf("%lld",f[p][n]-s[n]*s[n]);
	return 0;
}

  

转载于:https://www.cnblogs.com/MashiroSky/p/6240277.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值