|
| 1 | +// Rozwiązanie zadania 'Pojemniki' z II etapu XXXI OI. |
| 2 | +// Autor rozwiązania: Paweł Putra |
| 3 | +// Złożoność czasowa: O(n * log(n)) |
| 4 | +// Złożoność pamięciowa: O(n). |
| 5 | +// Punkty: 100 (upsolve) |
| 6 | + |
| 7 | +#include <bits/stdc++.h> |
| 8 | +using namespace std; |
| 9 | +using ll = long long; |
| 10 | +int32_t main() { |
| 11 | + ios_base::sync_with_stdio(0); |
| 12 | + int n; |
| 13 | + ll k; |
| 14 | + cin >> n >> k; |
| 15 | + |
| 16 | + multiset<pair<ll, int>> s; |
| 17 | + for (int i = 1; i <= n; i++) { |
| 18 | + ll x; |
| 19 | + cin >> x; |
| 20 | + s.insert({x, i}); |
| 21 | + } |
| 22 | + |
| 23 | + vector<vector<pair<int,ll>>> pojemniki; |
| 24 | + while (!s.empty()) { |
| 25 | + auto [min_ile, min_idx] = *s.begin(); |
| 26 | + // Jeśli minimum jest większe niż k, to suma objętości jest większa niż n * k. |
| 27 | + if (min_ile > k) { |
| 28 | + cout << "NIE\n"; |
| 29 | + return 0; |
| 30 | + } |
| 31 | + |
| 32 | + // Jeśli rozwiązanie istnieje, to istnieje też rozwiązanie, |
| 33 | + // w którym składnik o najmniejszej objętości jest tylko w jednym pojemniku. |
| 34 | + // Dowód: |
| 35 | + // Załóżmy, że w jakimś rozwiązaniu są dwa pojemniki, w których jest ten składnik. |
| 36 | + // Zawsze możemy przenieść ten składnik z pojemnika, w którym jest go mniej do tego drugiego, |
| 37 | + // zamieniając go z resztą składnika drugiego. Zmieści się na pewno bo sumaryczna objętość |
| 38 | + // tego składnika nie przekracza k. |
| 39 | + pojemniki.push_back({{min_idx, min_ile}}); |
| 40 | + ll zostalo = k - min_ile; |
| 41 | + if (zostalo > 0) { |
| 42 | + auto [max_ile, max_idx] = *(--s.end()); |
| 43 | + if (max_idx != min_idx) { |
| 44 | + s.erase(--s.end()); |
| 45 | + ll zabierane = min(max_ile, zostalo); |
| 46 | + if (zabierane < max_ile) { |
| 47 | + s.insert({max_ile - zostalo, max_idx}); |
| 48 | + } |
| 49 | + pojemniki.back().push_back({max_idx, zabierane}); |
| 50 | + } |
| 51 | + } |
| 52 | + |
| 53 | + // Nie można zrobić s.erase(s.begin()) bo maks mógł stać się nowym minem. |
| 54 | + s.erase(s.find({min_ile, min_idx})); |
| 55 | + } |
| 56 | + |
| 57 | + cout << "TAK\n"; |
| 58 | + for (int i = 0; i < n; i++) { |
| 59 | + if (i >= pojemniki.size()) { |
| 60 | + cout << "0\n"; |
| 61 | + continue; |
| 62 | + } |
| 63 | + cout << pojemniki[i].size() << " "; |
| 64 | + for (auto [idx, ile] : pojemniki[i]) cout << idx << " " << ile << " "; |
| 65 | + cout << "\n"; |
| 66 | + } |
| 67 | +} |
0 commit comments