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; }