zoukankan      html  css  js  c++  java
  • 「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;
    }
    
  • 相关阅读:
    快速幂
    快速幂
    快速排序的分治求解方法
    快速排序的分治求解方法
    合并排序的分治求解方法
    合并排序的分治求解方法
    重写ListView解决ListView内部ViewPaper滑动事件冲突问题
    HDU 4970(杭电多校#9 1011题)Killing Monsters(瞎搞)
    Java 反射机制[Field反射]
    【公告】博客数据异常已所有恢复
  • 原文地址:https://www.cnblogs.com/zcr-blog/p/13471632.html
Copyright © 2011-2022 走看看