#include <iostream>
#include <vector>
#include <numeric>
#include <algorithm>
using namespace std;
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
long long n, m, k;
if (!(cin >> n >> m >> k)) return 0;
vector<long long> nalesnikiMalejace;
vector<vector<long long>> stosyRosnace;
// 1. Wczytywanie i podział
for (int i = 0; i < n; ++i) {
vector<long long> obecnyStos(m);
for (int j = 0; j < m; ++j) {
cin >> obecnyStos[j];
}
// Czy największe są na górze?
if (m == 1 || obecnyStos[0] >= obecnyStos[m - 1]) {
for (long long wartosc : obecnyStos) nalesnikiMalejace.push_back(wartosc);
}
else {
stosyRosnace.push_back(obecnyStos);
}
}
// 2. Przygotowanie naleśników malejących
sort(nalesnikiMalejace.rbegin(), nalesnikiMalejace.rend());
vector<long long> prefMalejace(nalesnikiMalejace.size() + 1, 0);
for (size_t i = 0; i < nalesnikiMalejace.size(); ++i) {
prefMalejace[i + 1] = prefMalejace[i] + nalesnikiMalejace[i];
}
// 3. Przygotowanie pełnych stosów rosnących przy użyciu std::pair <suma, id>
vector<pair<long long, int>> pelneStosyRosnace;
for (size_t i = 0; i < stosyRosnace.size(); ++i) {
long long sumaStosu = 0;
for (long long wartosc : stosyRosnace[i]) sumaStosu += wartosc;
pelneStosyRosnace.push_back({ sumaStosu, (int)i });
}
sort(pelneStosyRosnace.rbegin(), pelneStosyRosnace.rend());
vector<long long> prefPelneRosnace(pelneStosyRosnace.size() + 1, 0);
vector<int> pozycjaWRankingach(stosyRosnace.size(), -1);
for (size_t i = 0; i < pelneStosyRosnace.size(); ++i) {
prefPelneRosnace[i + 1] = prefPelneRosnace[i] + pelneStosyRosnace[i].first;
pozycjaWRankingach[pelneStosyRosnace[i].second] = i;
}
long long maksymalnyZysk = 0;
// 4. Główna pętla i Wyszukiwanie Binarne
for (int i = -1; i < (int)stosyRosnace.size(); ++i) {
int maxNalesnikowCzesciowych = (i == -1) ? 0 : m - 1;
int pomijanaPozycja = (i == -1) ? -1 : pozycjaWRankingach[i];
vector<long long> sumyCzescioweAktualnegoStosu;
if (i != -1) {
sumyCzescioweAktualnegoStosu.assign(m + 1, 0);
for (int j = 0; j < m; ++j) {
sumyCzescioweAktualnegoStosu[j + 1] = sumyCzescioweAktualnegoStosu[j] + stosyRosnace[i][j];
}
}
for (int c = 0; c <= maxNalesnikowCzesciowych; ++c) {
long long pozostaleRuchy = k - c;
if (pozostaleRuchy < 0) continue;
long long zyskCzesciowy = (i == -1) ? 0 : sumyCzescioweAktualnegoStosu[c];
long long dostepnePelneStosy = stosyRosnace.size() - (i != -1 ? 1 : 0);
long long maxPelnychStosow = min((long long)dostepnePelneStosy, pozostaleRuchy / m);
long long brakiMalejacych = pozostaleRuchy - (long long)nalesnikiMalejace.size();
long long minPelnychStosow = 0;
if (brakiMalejacych > 0) {
minPelnychStosow = (brakiMalejacych + m - 1) / m;
}
if (minPelnychStosow > maxPelnychStosow) continue;
auto obliczZyskDla = [&](long long y) -> long long {
long long ruchyNaMalejace = pozostaleRuchy - y * m;
long long zyskPelneRosnace = 0;
if (pomijanaPozycja != -1 && pomijanaPozycja < y) {
zyskPelneRosnace = prefPelneRosnace[y + 1] - pelneStosyRosnace[pomijanaPozycja].first; // Odwołanie do .first
}
else {
zyskPelneRosnace = prefPelneRosnace[y];
}
long long zyskMalejace = prefMalejace[ruchyNaMalejace];
return zyskCzesciowy + zyskPelneRosnace + zyskMalejace;
};
// Binary Search
long long L = minPelnychStosow, R_bin = maxPelnychStosow;
while (L < R_bin) {
long long srodek = L + (R_bin - L) / 2;
if (obliczZyskDla(srodek) < obliczZyskDla(srodek + 1)) {
L = srodek + 1;
}
else {
R_bin = srodek;
}
}
maksymalnyZysk = max(maksymalnyZysk, obliczZyskDla(L));
}
}
cout << maksymalnyZysk;
return 0;
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 | #include <iostream> #include <vector> #include <numeric> #include <algorithm> using namespace std; int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); long long n, m, k; if (!(cin >> n >> m >> k)) return 0; vector<long long> nalesnikiMalejace; vector<vector<long long>> stosyRosnace; // 1. Wczytywanie i podział for (int i = 0; i < n; ++i) { vector<long long> obecnyStos(m); for (int j = 0; j < m; ++j) { cin >> obecnyStos[j]; } // Czy największe są na górze? if (m == 1 || obecnyStos[0] >= obecnyStos[m - 1]) { for (long long wartosc : obecnyStos) nalesnikiMalejace.push_back(wartosc); } else { stosyRosnace.push_back(obecnyStos); } } // 2. Przygotowanie naleśników malejących sort(nalesnikiMalejace.rbegin(), nalesnikiMalejace.rend()); vector<long long> prefMalejace(nalesnikiMalejace.size() + 1, 0); for (size_t i = 0; i < nalesnikiMalejace.size(); ++i) { prefMalejace[i + 1] = prefMalejace[i] + nalesnikiMalejace[i]; } // 3. Przygotowanie pełnych stosów rosnących przy użyciu std::pair <suma, id> vector<pair<long long, int>> pelneStosyRosnace; for (size_t i = 0; i < stosyRosnace.size(); ++i) { long long sumaStosu = 0; for (long long wartosc : stosyRosnace[i]) sumaStosu += wartosc; pelneStosyRosnace.push_back({ sumaStosu, (int)i }); } sort(pelneStosyRosnace.rbegin(), pelneStosyRosnace.rend()); vector<long long> prefPelneRosnace(pelneStosyRosnace.size() + 1, 0); vector<int> pozycjaWRankingach(stosyRosnace.size(), -1); for (size_t i = 0; i < pelneStosyRosnace.size(); ++i) { prefPelneRosnace[i + 1] = prefPelneRosnace[i] + pelneStosyRosnace[i].first; pozycjaWRankingach[pelneStosyRosnace[i].second] = i; } long long maksymalnyZysk = 0; // 4. Główna pętla i Wyszukiwanie Binarne for (int i = -1; i < (int)stosyRosnace.size(); ++i) { int maxNalesnikowCzesciowych = (i == -1) ? 0 : m - 1; int pomijanaPozycja = (i == -1) ? -1 : pozycjaWRankingach[i]; vector<long long> sumyCzescioweAktualnegoStosu; if (i != -1) { sumyCzescioweAktualnegoStosu.assign(m + 1, 0); for (int j = 0; j < m; ++j) { sumyCzescioweAktualnegoStosu[j + 1] = sumyCzescioweAktualnegoStosu[j] + stosyRosnace[i][j]; } } for (int c = 0; c <= maxNalesnikowCzesciowych; ++c) { long long pozostaleRuchy = k - c; if (pozostaleRuchy < 0) continue; long long zyskCzesciowy = (i == -1) ? 0 : sumyCzescioweAktualnegoStosu[c]; long long dostepnePelneStosy = stosyRosnace.size() - (i != -1 ? 1 : 0); long long maxPelnychStosow = min((long long)dostepnePelneStosy, pozostaleRuchy / m); long long brakiMalejacych = pozostaleRuchy - (long long)nalesnikiMalejace.size(); long long minPelnychStosow = 0; if (brakiMalejacych > 0) { minPelnychStosow = (brakiMalejacych + m - 1) / m; } if (minPelnychStosow > maxPelnychStosow) continue; auto obliczZyskDla = [&](long long y) -> long long { long long ruchyNaMalejace = pozostaleRuchy - y * m; long long zyskPelneRosnace = 0; if (pomijanaPozycja != -1 && pomijanaPozycja < y) { zyskPelneRosnace = prefPelneRosnace[y + 1] - pelneStosyRosnace[pomijanaPozycja].first; // Odwołanie do .first } else { zyskPelneRosnace = prefPelneRosnace[y]; } long long zyskMalejace = prefMalejace[ruchyNaMalejace]; return zyskCzesciowy + zyskPelneRosnace + zyskMalejace; }; // Binary Search long long L = minPelnychStosow, R_bin = maxPelnychStosow; while (L < R_bin) { long long srodek = L + (R_bin - L) / 2; if (obliczZyskDla(srodek) < obliczZyskDla(srodek + 1)) { L = srodek + 1; } else { R_bin = srodek; } } maksymalnyZysk = max(maksymalnyZysk, obliczZyskDla(L)); } } cout << maksymalnyZysk; return 0; } |
English