CF505E Mr. Kitayuta vs. Bamboos 【二分答案】【贪心】

二分答案由最优问题变为可行性问题

首先可以发现,因为一个竹子在一天可以被砍多次,那么其实在不浪费的情况下一个竹子越往后被砍肯不是不会更劣的(因为如果砍成小于0了就会浪费)

然而我们并好不知道一个竹子应该被砍的准确时间,所以我们把倒着看这个问题,从最后一天开始 -- 所有的竹子的高度均为mid,每天竹子会减小a[i],你可以增加k个p给一些竹子,最后能否让所有竹子均大于等于他们的初始高度h[i]

这样一来,我们直接给最需要被使用技能竹子使用技能即可,因为这一定是最晚的时候时间,也是最优的

对于一些有下界没有上界的贪心问题,不妨试试倒着来看

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define gi get_int()
const int MAXN = 2e6;
#define int long long
int get_int()
{
  int x = 0, y = 1;
  char ch = getchar();
  while (!isdigit(ch) && ch != '-')
    ch = getchar();
  if (ch == '-')
    y = -1, ch = getchar();
  while (isdigit(ch))
    x = x * 10 + ch - '0', ch = getchar();
  return x * y;
}

int plus[MAXN], m, n, k, p, h[MAXN], a[MAXN];

class Heap
{
public:
  int height, index;
} heap[MAXN];
int hNum;
int operator< (const Heap& a1, const Heap& b)
{
  int valueA = (a1.height + plus[a1.index] * p) / a[a1.index];
  int valueB = (b.height + plus[b.index] * p) / a[b.index];
  return valueA > valueB;
}

int check(int mid)
{
  memset(plus, 0, sizeof(plus));
  hNum = 0;
  for (int i = 0; i < n; i++) {
    if ((mid - h[i]) / a[i] < m) {
      heap[hNum].height = mid;
      heap[hNum].index = i;
      hNum++;
    }
  }
  if (hNum == 0) return 1;
  std::make_heap(heap, heap + hNum);
  for (int i = 0; i < m; i++) {
    for (int j = 0; j < k; j++) {
      int index = heap[0].index, height = heap[0].height;
      std::pop_heap(heap, heap + hNum);
      hNum--;
      if (((height + plus[index] * p) / a[index]) < i + 1) return false;
      plus[index]++;
      if (height + plus[index] * p - a[index] * m < h[index]) {
        std::push_heap(heap, heap + hNum);
        hNum++;
      }
      if (hNum == 0)
        return true;
    }
  }
  return hNum == 0;
}

signed main()
{
  n = gi, m = gi, k = gi, p = gi;
  for (int i = 0; i < n; i++) {
    h[i] = gi;
    a[i] = gi;
  }
  int l = 0, r = 1e16, ans = -1;
  while (l <= r) {
    int mid = (l + r) / 2;
    if (check(mid) == true) {
      r = mid - 1;
      ans = mid;
    } else {
      l = mid + 1;
    }
  }
  std::cout << ans;

  return 0;
}
上一篇:TLAB 与堆可解析性


下一篇:数据结构第三次上机实验