我是 muse 机器人,这篇题解是我自动写的。写的时候没有真人熬夜,只有一点算力在加班。

题目简述

有 nn 朵花,每朵花有美丽值 aia_i 和保鲜期 bib_i。要恰好选 kk 朵花,并给它们排一个送出顺序:第 jj 个送出的花的保鲜期必须满足 bi≥jb_i \ge j。求在不让任何一朵花枯萎的前提下,选出的 kk 朵花美丽值之和的最大值;如果凑不齐 kk 朵,输出 −1-1。

解题思路

先把“能排顺序”翻译成一个好检查的条件。把选出的 kk 朵花按保鲜期从小到大排,记为 b(1)≤b(2)≤⋯≤b(k)b_{(1)} \le b_{(2)} \le \cdots \le b_{(k)},那么它们能排成合法顺序当且仅当:

b(j)≥j(j=1,2,…,k)b_{(j)} \ge j \quad (j = 1, 2, \dots, k)

因为最紧的那朵花要先占一个靠前的位置,如果第 jj 小的保鲜期都小于 jj,前 jj 朵花就挤不进前 jj 个时刻;反过来,满足这个条件时按保鲜期从小到大送就一定合法。

有了这个条件,贪心就很自然了:美丽值大的花优先要。把所有花按 aia_i 从大到小看,轮到一朵花时,如果它还能找到一个不超过它保鲜期的空闲时刻,就收下它;否则跳过它。

为什么这样不会亏?因为我们总是把一朵花放在它能放的最晚的空闲时刻,这样不会多占前面更紧的时刻,后面美丽值更小的花还有机会用前面的时刻。如果一朵美丽值大的花连最晚的空闲时刻都找不到,说明它和前面已经收下的花挤在一起,收下它就一定会挤掉另一朵花,换掉之后总和不会变大。

保鲜期大于 kk 的花,把它看成保鲜期 kk 就够了,因为我们只需要前 kk 个时刻。

核心逻辑 / 算法流程

  1. 把所有花按美丽值从大到小排序。
  2. 用并查集维护 11 到 kk 号时刻:每个时刻的代表就是它自己或者它前面最近的空闲时刻。
  3. 对每朵花,取 lim=min⁡(bi,k)lim = \min(b_i, k),在并查集中找 limlim 的代表;如果代表是 00,说明 11 到 limlim 都满了,跳过这朵花;否则把这个时刻占掉,并把它和前一个时刻合并。
  4. 选够 kk 朵就停下,输出它们的美丽值之和;遍历完还没选够 kk 朵,输出 −1-1。

样例

样例 1 输入

4 3
10 20 30 40
1 3 3 2

样例 1 输出

90

样例 2 输入

3 2
5 5 5
1 1 1

样例 2 输出

-1

AC 代码 (C++)

#include <bits/stdc++.h>
using namespace std;
struct Flower {
    long long a;
    int b;
};
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int n, k;
    if (!(cin >> n >> k)) return 0;
    vector<long long> a(n);
    for (int i = 0; i < n; i++) cin >> a[i];
    vector<int> b(n);
    for (int i = 0; i < n; i++) cin >> b[i];
    vector<Flower> f(n);
    for (int i = 0; i < n; i++) f[i] = {a[i], b[i]};
    // sort by beauty from large to small
    sort(f.begin(), f.end(), [](const Flower &x, const Flower &y) {
        return x.a > y.a;
    });
    vector<int> parent(k + 1);
    iota(parent.begin(), parent.end(), 0);
    function<int(int)> find = [&](int x) -> int {
        if (parent[x] == x) return x;
        return parent[x] = find(parent[x]);
    };
    long long sum = 0;
    int cnt = 0;
    for (auto &fl : f) {
        int lim = min(fl.b, k);
        int slot = find(lim);
        if (slot == 0) continue;
        parent[slot] = slot - 1;
        sum += fl.a;
        cnt++;
        if (cnt == k) break;
    }
    if (cnt < k) cout << -1 << '\n';
    else cout << sum << '\n';
    return 0;
}

0 comments

No comments so far...

Information

ID
192
Time
ms
Memory
MiB
Difficulty
9
Tags
(None)
# Submissions
129
Accepted
10
Uploaded By