Algoritmul, pas cu pas
Calculul monedelor. Sortez punctajele crescător. moneda[0] = punctaj[0]; pentru : dacă punctaj[i] == punctaj[i-1] atunci moneda[i] = moneda[i-1], altfel moneda[i] = punctaj[i] * (i+1). (Monedele cresc, deci sunt deja sortate.)
Cerința 2 — perechi divizibile cu .
- Grupez monedele după restul modulo :
cnt[r]. - O pereche are suma divizibilă cu dacă resturile se completează: cu .
- Adun
cnt[r] * cnt[K-r]pentru , plus și, dacă e par, .
Cerința 3 — cel mai mare prag .
- Pentru un fix, numărul maxim de perechi disjuncte cu suma se obține cu doi pointeri pe monedele sortate: dacă
moneda[l] + moneda[r] > X, formez pereche și avansez ambii; altfelmoneda[l]e prea mică pentru oricine (chiar și cu cel mai mare partener), deci o elimin. - Acest număr scade când crește, deci caut binar cel mai mare pentru care numărul de perechi e cel puțin .
Complexitate: (sortare) + pentru căutarea binară a cerinței 3.
Soluția în C++
#include <fstream>
#include <vector>
#include <algorithm>
using namespace std;
ifstream fin("algocoin.in");
ofstream fout("algocoin.out");
int main() {
int C;
long long N, K, P;
fin >> C >> N >> K >> P;
vector<long long> punctaj(N);
for (auto &x : punctaj) fin >> x;
sort(punctaj.begin(), punctaj.end());
vector<long long> moneda(N);
moneda[0] = punctaj[0];
for (int i = 1; i < N; i++) {
if (punctaj[i] == punctaj[i - 1]) moneda[i] = moneda[i - 1];
else moneda[i] = punctaj[i] * (long long)(i + 1); // rang i+1
}
if (C == 1) {
for (int i = 0; i < N; i++) {
fout << moneda[i];
fout << (i + 1 < N ? ' ' : '\n');
}
} else if (C == 2) {
vector<long long> cnt(K, 0);
for (int i = 0; i < N; i++) cnt[moneda[i] % K]++;
long long pairs = 0;
for (long long r = 0; r <= K / 2; r++) {
long long comp = (K - r) % K;
if (r == comp) pairs += cnt[r] * (cnt[r] - 1) / 2; // r și r
else if (r < comp) pairs += cnt[r] * cnt[comp];
}
fout << pairs << "\n";
} else { // C == 3
sort(moneda.begin(), moneda.end()); // deja crescătoare, dar siguri
auto maxPerechi = [&](long long X) -> long long {
int i = 0, j = (int)N - 1;
long long c = 0;
while (i < j) {
if (moneda[i] + moneda[j] > X) { c++; i++; j--; }
else i++; // cel mai mic nu poate forma nicio pereche validă
}
return c;
};
long long lo = 0, hi = (moneda[N - 1] + moneda[N - 2]) / K + 1, best = 0;
while (lo <= hi) {
long long mid = (lo + hi) / 2;
if (maxPerechi(mid * K) >= P) { best = mid * K; lo = mid + 1; }
else hi = mid - 1;
}
fout << best << "\n";
}
return 0;
}Greșeli frecvente
- Folosești
intpentru monede — moneda poate fi , decilong longobligatoriu, altfel overflow. - Numeri dublu la cerința 2 — pentru restul și pentru (când e par) perechile sunt în interiorul aceleiași grupe: folosește , nu .
- Încerci toți multiplii lui pe rând la cerința 3 — cu valori până la ar fi prea mulți; folosește monotonia (perechi scad când crește) și caută binar.