Loading

5.9 CW 模拟赛 T2. 电梯

思路

\(w\) 全为 \(0\) 显然可贪

考虑 \(w = 1\) 的情况
这显然不能背包

做法 \(1\)

注意到任何 \(2^w\) 可以视作 \(2^w\)\(2^0\), 然后贪心
完全无法理解啊, 太超模了/kk

做法 \(2\)

首先一个性质是如果你还能放一个货物那你一定要放进去, 不劣
考虑 \(w\) 最小的那一堆, 不难发现你一定是两个两个放进去的, 因为单放亏得

这启发我们: 对两个重量最小的货物做匹配, 将它们合并成更大的货物, 不影响答案, 因为它总是两个两个加进背包里的
为了最小化时间的限制, 我们还需要做一个贪心, 即将重量最小的货物排成一排按照 \(f\) 降序排序, 相邻两个一组, 这样得到的新的货物的 \(f\) 的限制最松
奇数个时会剩余一个重量最小楼层最小的货物, 此时直接将其重量翻倍已经不会有影响了, 因为此时除了他以外最小的 \(w\) 也是他的两倍, 只要这一组留下了空隙那么一定是足够再放进去两个 \(2^w\) 的, 否则一定放不了

本质上是一个性质: 容积和物品大小都是 \(2\) 的幂次, 那么只要你能放进去一个 \(2^w\), 意味着你还可以再放一个

有了这个性质, 我们不妨从小到大合并 \(w\), 然后就做完了

实例代码
#include <bits/stdc++.h>
using namespace std;
#ifdef LOCAL
#define debug(...) fprintf(stderr, ##__VA_ARGS__)
#else
#define debug(...) void(0)
#endif
typedef long long LL;
struct node {
  int f, c;
};
int n, m;
vector<node> buc[500010];
LL ans = 0;
int main() {
#ifndef LOCAL
#ifndef NF
  freopen("lift.in", "r", stdin);
  freopen("lift.out", "w", stdout);
#endif
  cin.tie(nullptr)->sync_with_stdio(false);  
#endif
  cin >> n >> m;
  for (int i = 1, w, c, f; i <= n; i++) cin >> c >> w >> f, buc[w].push_back({f, c});
  vector<node> vec;
  for (int w = 0; w < m; w++) {
    vector<node> now;
    auto itl = vec.begin(), itr = buc[w].begin();
    sort(buc[w].begin(), buc[w].end(), [&](node lhs, node rhs) { return lhs.f > rhs.f; });
    while (itl != vec.end() || itr != buc[w].end()) {
      auto it = itl != vec.end() && (itr == buc[w].end() || itl->f > itr->f) ? itl++ : itr++;
      if (!now.empty() && now.back().f == it->f) now.back().c += it++->c;
      else now.push_back(move(*it++));
    }
    vec.clear();
    int lst = -1;
    for (auto&& e : now) if (e.c) {
      if (~lst) vec.push_back({lst, 1}), e.c -= 1, lst = -1;
      if (e.c > 1) vec.push_back({e.f, e.c >> 1});
      if (e.c & 1) lst = e.f;
    }
    if (~lst) vec.push_back({lst, 1});
    debug("after w = %d, vec = ", w);
    for (auto&& e : vec) debug("(%d, %d), ", e.f, e.c);
    debug("\n");
  }
  for (auto&& e : vec) ans += 1ll * e.f * e.c, debug("(%d, %d)\n", e.f, e.c);
  for (auto&& e : buc[m]) ans += 1ll * e.f * e.c, debug("(%d, %d)\n", e.f, e.c);
  cout << ans << endl;
  return 0;
}
posted @ 2025-05-14 21:34  Yorg  阅读(15)  评论(0)    收藏  举报