• [Codechef CCC]Hit the coconuts


    题意: (N) 个椰子, 第 (i) 个需要敲 (a_i) 下才能打开,问最坏情况下最少要敲多少下才能打开 (k) 个椰子。

    不妨设 (a_i le a_{i + 1})

    要敲开一个椰子,现在有两种方法:

    1. 随便拿起一个椰子不停地敲,最多要 (a_n) 次。
    2. 有目的性地想要敲开某个椰子 (a_i),可以发现最优的策略就是每个椰子都敲 (a_i) 次,最多要敲 (a_i imes(n - i + 1)) 次,所有情况下取最小值。

    第二种情况实际上包含了第一种。

    那么要敲开 (k) 个椰子,也有两种方法:

    1. 每次都随便拿一个敲开,最多要 (a_n + a_{n - 1}+ dots + a_{n - k + 1}) 次。
    2. (k) 个椰子 (a_{b_1}, a_{b_2}, dots, a_{b_k}(b_i < b_{i + 1})),有目的性地敲开它们。发现最优策略下最多要敲 (sum_{i = 1}^k (a_{b_i} - a_{b_i - 1}) imes (n - b_i + 1)) 次,其中 (a_{b_0} = 0),所有情况下取最小值。

    第二种情况也包含了第一种。

    因此考虑第二种情况的求解,设 (dp[i][k]) 表示前 (i) 个椰子敲开 (k) 个(包括第 (i) 个椰子)的最少次数。

    [dp[i][k] = min{dp[j][k - 1] + (a_i - a_j) imes (n - i + 1)} ]

    这显然是一个斜率优化的形式,化一下式子(第二维省略):

    [dp[i] = min{a_j imes (i - n - 1) + dp[j]} + a_i imes (n - i + 1) ]

    设直线 (L_j(x) = a_j cdot x + dp[j]),求 (min L_j(i - n - 1)),斜率和横坐标都是递增的,可以用栈维护一个上凸壳,复杂度 (O(nk + nlog n))

    #include <bits/stdc++.h>
    #ifdef LOCAL
    #define dbg(args...) std::cerr << "33[32;1m" << #args << " -> ", err(args)
    #else
    #define dbg(...)
    #endif
    inline void err() { std::cerr << "33[0m
    "; }
    template<class T, class... U>
    inline void err(const T &x, const U &... a) { std::cerr << x << ' '; err(a...); }
    template <class T>
    inline void readInt(T &w) {
      char c, p = 0;
      while (!isdigit(c = getchar())) p = c == '-';
      for (w = c & 15; isdigit(c = getchar());) w = w * 10 + (c & 15);
      if (p) w = -w;
    }
    template <class T, class... U>
    inline void readInt(T &w, U &... a) { readInt(w), readInt(a...); }
    template <class T, class U>
    inline bool smin(T &x, const U &y) { return y < x ? x = y, 1 : 0; }
    template <class T, class U>
    inline bool smax(T &x, const U &y) { return x < y ? x = y, 1 : 0; }
    
    typedef long long LL;
    typedef std::pair<int, int> PII;
    
    constexpr int N(1005);
    int n, k, a[N];
    LL dp[N];
    struct Line {
      int k; LL b;
      Line(int k = 0, LL b = 0): k(k), b(b) {}
      inline LL func(int x) { return 1LL * k * x + b; }
      inline bool check(const Line &p, const Line &q) const {
        return (b - p.b) * (k - q.k) > (b - q.b) * (k - p.k);
      }
    } q[N];
    int main() {
      int t; readInt(t);
      while (t--) {
        readInt(n, k);
        for (int i = 1; i <= n; i++) readInt(a[i]);
        std::sort(a + 1, a + 1 + n);
        for (int i = 1; i <= n; i++) dp[i] = 1e9;
        for (int c = 0, r; c < k; c++) {
          q[r = 1] = Line(a[c], dp[c]);
          for (int i = c + 1; i <= n; i++) {
            int x = i - n - 1;
            while (r > 1 && q[r].func(x) >= q[r - 1].func(x)) r--;
            Line now = Line(a[i], dp[i]);
            dp[i] = q[r].func(x) - 1LL * a[i] * x;
            while (r > 1 && !now.check(q[r], q[r - 1])) r--;
            q[++r] = now;
          }
        }
        LL ans = dp[k];
        for (int i = k + 1; i <= n; i++) smin(ans, dp[i]);
        printf("%lld
    ", ans);
      }
      return 0;
    }
    
  • 相关阅读:
    001 Python网络爬虫与信息提取 课程前序
    004 JQuery (010
    Vuex的元素对象
    003 JQuery (009
    002 JQuery (004
    001 JQuery (001
    Vuex简介
    axios实例与模块封装
    axios拦截器
    015 Javascript(152
  • 原文地址:https://www.cnblogs.com/HolyK/p/13967211.html
Copyright © 2020-2023  润新知