【AtCoder】ABC 461 C - Variety

C - Varietyatcoder.jp favicon

実行時間制限: 2 sec / メモリ制限: 1024 MiB / Difficulty: 332 / NoviSteps: 3Q / 配点: 300 点

問題概要

NN 個の宝石があり、 ii 番目の宝石の色は CiC_i で価値は ViV_i である。

この NN 個の宝石の中から KK 個を選ぶことを考える。 ただし、選んだ宝石の色が MM 種類以上なければなければならない。

このとき、選んだ宝石の価値の総和としてありうる最大値を求めよ。

制約

  • 1MKN2×1051 \leq M \leq K \leq N \leq 2 \times 10^5
  • 1CiN1 \leq C_i \leq N
  • 1Vi1091 \leq V_i \leq 10^9
  • MM 種類以上の色の宝石が存在する
  • 入力される値はすべて整数

考察

色の種類を無視すれば、単純に価値の高い方から KK 個を選べばよい。

そのような選び方で色の種類数が足りない場合は、まだ選ばれていない色の宝石を追加する必要があり、代わりに同じ色で2個目以降の宝石を削除しなければならない。

つまり、

  • まだ選んでいない色から「その色で最も価値が高い宝石」を追加候補にする
  • すでに選んでいる宝石のうち「同じ色で2個目以降の宝石」を削除候補にする

としたうえで、最も価値の高い追加候補と、最も価値の低い削除候補を交換するような操作を、色の種類数が MM 以上になるまで繰り返せばよい。

実装例

CPP
1.#include <bits/stdc++.h>
2.using namespace std;
3.
4.#define all(x) (x).begin(), (x).end()
5.#define rall(x) (x).rbegin(), (x).rend()
6.#define rep(i, start, end) for (auto i = (start); (i) < (end); (i)++)
7.
8.using ll = long long;
9.using Pair_ll = pair<ll, ll>;
10.
11.template <typename T>
12.inline bool chmax(T& a, T b) { return ((a < b) ? (a = b, true) : (false)); }
13.
14.// ======================================== //
15.
16.int main()
17.{
18. int N, K, M;
19. cin >> N >> K >> M;
20. vector<Pair_ll> jewels(N);
21. rep(i, 0, N) cin >> jewels[i].first >> jewels[i].second;
22.
23. sort(all(jewels), [](auto& a, auto& b) {
24. if (a.second == b.second)
25. return a.first > b.first;
26. return a.second > b.second;
27. });
28.
29. vector<int> cnt(N, 0);
30. vector<ll> remove_cands;
31.
32. ll ans = 0;
33. int kinds = 0;
34. rep(i, 0, K) {
35. auto [c, v] = jewels[i];
36. c--;
37.
38. ans += v;
39.
40. if (cnt[c] == 0) {
41. kinds++;
42. }
43. else {
44. remove_cands.push_back(v);
45. }
46.
47. cnt[c]++;
48. }
49.
50. if (kinds >= M) {
51. cout << ans << endl;
52. return 0;
53. }
54.
55. vector<ll> best_add(N, -1);
56. rep(i, K, N) {
57. auto [c, v] = jewels[i];
58. c--;
59.
60. if (cnt[c] == 0)
61. chmax(best_add[c], v);
62. }
63.
64. vector<ll> add_cands;
65. rep(c, 0, N) {
66. if (best_add[c] != -1) {
67. add_cands.push_back(best_add[c]);
68. }
69. }
70.
71. sort(rall(add_cands));
72. sort(all(remove_cands));
73.
74. rep(i, 0, M - kinds) {
75. ans += add_cands[i];
76. ans -= remove_cands[i];
77. }
78.
79. cout << ans << endl;
80.
81. return 0;
82.}
Submission #76508721 - AtCoder Beginner Contest 461atcoder.jp favicon

実装時間: 15分

コメント

公式解説でいうと実装例は解法2にあたるが、解法1の方が実装は簡単そう。