zoukankan      html  css  js  c++  java
  • 【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;
    }
    

      

  • 相关阅读:
    「Baltic2015」Network
    noip模拟赛 蒜头君的排序
    noip模拟赛 蒜头君的兔子
    codevs2171 棋盘覆盖
    noip模拟赛 蒜头君的坐骑
    noip模拟赛 蒜头君的树
    noip模拟赛 蒜头君打地鼠
    noip模拟赛 密码
    noip模拟赛 轰炸
    noip模拟赛 毁灭
  • 原文地址:https://www.cnblogs.com/MashiroSky/p/6240277.html
Copyright © 2011-2022 走看看