• 「SDOI2016」征途(斜率优化)


    先来化一下方差的式子:

    [S_m^2=frac{1}{m} imes sum_{i=1}^m(a_i-frac{1}{m}sum_{j=1}^{m}a_j)^2\ =frac{1}{m} imes (sum_{i=1}^ma_i^2-sum_{i=1}^ma_i imes frac{2}{m}sum_{i=1}^ma_i+frac{(sum_{i=1}^ma_i)^2}{m})\ =frac{1}{m} imes (sum_{i=1}^m a_i^2-frac{(sum_{i=1}^ma_i)^2}{m}) ]

    乘一个 (m^2) 约成下面这样:

    [m^2 imes S_m^2=msum_{i=1}^{m}a_i^2-(sum)^2 ]

    后面是个常量,不管,我们来最小化前面这个东西。

    区间划分问题容易想到dp,这里还有个数的限制所以再加一维。可以得到我们的状态 (f[i][j]) 代表到第 (i) 个,分成 (j) 段。有转移方程 (f[i][j]=min{f[k][j-1]+(a[i]-a[k])^2})(a) 是前缀和。

    拆开和我们发现可以斜率优化,并且 (a) 是单调的,因为是求最小值所以用下凸壳。

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 3010;
    int n, m;
    int a[N], f[N][N];
    int q[N];
    double X(int i) {
    	return a[i];
    }
    double Y(int i, int j) {
    	return a[i] * a[i] + f[i][j - 1];
    }
    double slope(int i, int j, int k) {
    	return (Y(j, k) - Y(i, k)) / (X(j) - X(i));
    }
    int main() {
    	memset(f, 0x3f, sizeof(f));
    	cin >> n >> m;
    	for (int i = 1; i <= n; i++) cin >> a[i], a[i] += a[i - 1];
    	for (int i = 1; i <= n; i++) f[i][1] = a[i] * a[i];
    	for (int j = 2; j <= m; j++) {
    		int head = 1, tail = 0;
    		q[++tail] = j - 1;
    		for (int i = j; i <= n; i++) {
    			f[i][j] = a[i] * a[i];
    			while (head < tail && slope(q[head], q[head + 1], j) <= 2.0 * a[i]) head++;
    			f[i][j] += Y(q[head], j) - 2 * a[i] * X(q[head]);
    			while (head < tail && slope(q[tail - 1], q[tail], j) >= slope(q[tail], i, j)) tail--;
    			q[++tail] = i;
    		}
    	}
    	cout << m * f[n][m] - a[n] * a[n];
    	return 0;
    }
    
  • 相关阅读:
    深浅拷贝
    生成式、生成器、迭代对象、迭代器
    memcached
    redis安装配置
    基于docker搭建mysql主从复制架构
    centos 安装 最新版本的docker
    Linux小技巧
    神奇的'license': 'AGPL 3.0'标签报错
    新博客重新开通了
    通过linkserver不能调远程表值函数
  • 原文地址:https://www.cnblogs.com/zcr-blog/p/13471632.html
Copyright © 2020-2023  润新知