• [IOI 2000]邮局


    Description

    题库链接

    给你 (n) 个村庄,你需要在这 (n) 个村庄中选出 (m) 个建邮局。要使得每个村庄到最近的邮局距离和最小。

    (1leq nleq 3000,1leq mleq 300)

    Solution

    (f_{i,j}) 表示前 (i) 个村庄建 (j) 个邮局最少的距离和。那么 (f_{i,j}=min{f_{k,j-1}+w(k+1,i)}),其中 (w) 表示这区间内的村庄建一个邮局的距离和。这是可以 (O(1)) 算出的。

    于是我们考虑一下这个 (f) 的性质,令 (ileq i',jleq j'),那么有 (f_{i,j'}+f_{i',j}geq f_{i,j}+f_{i',j'})。这个感性理解一下就是较多的邮局建到较少的村庄中一定比建到较多的村庄中浪费。

    因此我们的 (f) 是满足四边形不等式的。因此记 (s_{i,j}) 表示 (f_{i,j}) 的最优决策点,那么是可以用四边形不等式定理优化的,具体可以参考这篇文章

    将枚举区间变成 (s_{i,j-1}leq kleq s_{i+1,j}),那么复杂度为 (O(n^2))

    Code

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 3000+5;
    
    int n, m, x[N], f[N][305], s[N][305];
    
    int w(int l, int r) {
        int mid = (l+r)>>1;
        if ((l+r)&1) return x[r]-x[mid]*2+x[l-1];
        else return x[r]-x[mid]-x[mid-1]+x[l-1];
    }
    int main() {
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n; i++) scanf("%d", &x[i]);
        sort(x+1, x+n+1);
        for (int i = 1; i <= n; i++) x[i] += x[i-1], f[i][1] = w(1, i);
        for (int i = 1; i <= m; i++) s[n+1][i] = n;
        for (int j = 2; j <= m; j++)
            for (int i = n; i >= 1; i--) {
                f[i][j] = ~0u>>1;
                for (int k = s[i][j-1]; k <= s[i+1][j]; k++) 
                    if (f[k][j-1]+w(k+1, i) < f[i][j])
                        f[i][j] = f[k][j-1]+w(k+1, i), s[i][j] = k;
            }
        printf("%d
    ", f[n][m]);
        return 0;
    }
  • 相关阅读:
    cube.js 上下文实践的一些说明
    sitespeed.io 开源web 性能监控&&优化工具集
    sideway/joi js 强大的data schma 校验框架
    cube.js 最新版本的一些特性
    cube.js 支持的类型以及格式化
    cube.js 多租户模式使用一个说明
    airbyte 基于singer 扩展的EL 平台
    cube.js dimensions 的一些说明
    cube.js measures 的一些说明
    cube.js 上下文变量
  • 原文地址:https://www.cnblogs.com/NaVi-Awson/p/12680456.html
Copyright © 2020-2023  润新知