• [HDU 3480]Division


    Description

    题库链接

    给你一个大小为 (n) 的集合,将其划分为若干子集。要求所有子集取并集为全集。每一个子集的贡献为该集合内最大元素与最小元素差的平方。求所有划分中最少的贡献和。

    (1leq nleq 10000,1leq mleq 5000)

    Solution

    将集合内元素从大到小排序。由贪心的思想,这一问题转换为将这一序列划分为 (m) 段,最小化贡献和。

    可以 DP,(f_{i,j}) 为前 (i) 个元素划分为 (j) 段的最小贡献。这一 DP 同[HDU 2829]Lawrence

    Code

    #include <bits/stdc++.h>
    #define w(i, j) ((a[j]-a[i])*(a[j]-a[i]))
    using namespace std;
    const int N = 5000+5;
    
    int f[N<<1][N], n, m, a[N<<1], s[N<<1][N], id;
    
    void work() {
        scanf("%d%d", &n, &m); ++id;
        for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
        sort(a+1, a+n+1);
        for (int i = 1; i <= n; i++)
            f[i][1] = (a[i]-a[1])*(a[i]-a[1]), s[i][1] = 1;
        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[i][j] > f[k-1][j-1]+w(k, i)) {
                        f[i][j] = f[k-1][j-1]+w(k, i);
                        s[i][j] = k;
                    }
            }
        printf("Case %d: %d
    ", id, f[n][m]);
    }
    int main() {
        int t; scanf("%d", &t);
        while (t--) work();
        return 0;
    }
  • 相关阅读:
    对SpringIOC、AOP的理解
    Java后台与VUE跨域交接
    贼简单的Shiro框架之粗粒度控制菜单栏
    Json
    Spring MVC小DEMO
    面试问题
    多线程理解
    了解java语言
    单点登录如何设计
    进程的创建和调度分析
  • 原文地址:https://www.cnblogs.com/NaVi-Awson/p/13445016.html
Copyright © 2020-2023  润新知