Algoritmul, pas cu pas
Notez prefixMario[i] și prefixWario[i] energiile consumate până la săritura , și , cu .
Cerința 1 — diferența maximă. Parcurg de la la și rețin indicele cu maxim (primul, dacă sunt mai multe).
Cerința 2 — fereastra de lungime a lui Mario.
- Calculez suma primei ferestre .
- Glisez fereastra: la mutare, adaug noul element din dreapta și scad pe cel ieșit din stânga (în ).
- Rețin începutul cu suma maximă (la egalitate, cel mai mic).
Cerința 3 — segment cu energii egale.
- Energiile pe sunt egale .
- Deci caut o valoare care se repetă în șirul .
- Țin într-un dicționar prima poziție a fiecărei valori; la o repetare am segmentul . Aleg minim, apoi minim.
Complexitate: pentru cerințele 1 și 2, în medie pentru cerința 3 (cu dicționar).
Soluția în C++
#include <fstream>
#include <vector>
#include <unordered_map>
using namespace std;
ifstream fin("mario.in");
ofstream fout("mario.out");
int main() {
int C, N, K;
fin >> C >> N >> K;
vector<long long> M(N + 1), W(N + 1), pM(N + 1, 0), pW(N + 1, 0);
for (int i = 1; i <= N; i++) fin >> M[i];
for (int i = 1; i <= N; i++) fin >> W[i];
for (int i = 1; i <= N; i++) {
pM[i] = pM[i - 1] + M[i];
pW[i] = pW[i - 1] + W[i];
}
if (C == 1) {
long long best = -1;
int bi = 0;
for (int i = 1; i <= N; i++) {
long long d = pM[i] - pW[i];
if (d < 0) d = -d;
if (d > best) { best = d; bi = i; }
}
fout << bi << "\n";
} else if (C == 2) {
long long s = 0;
for (int i = 1; i <= K; i++) s += M[i]; // prima fereastră
long long best = s;
int bi = 1;
for (int i = 2; i + K - 1 <= N; i++) {
s += M[i + K - 1] - M[i - 1]; // glisăm fereastra în O(1)
if (s > best) { best = s; bi = i; }
}
fout << bi << "\n";
} else { // C == 3
unordered_map<long long, int> prima; // valoare D -> prima poziție
int bst = -1, bdr = -1;
for (int r = 0; r <= N; r++) {
long long d = pM[r] - pW[r];
auto it = prima.find(d);
if (it != prima.end()) {
int st = it->second + 1, dr = r;
if (bst == -1 || st < bst || (st == bst && dr < bdr)) { bst = st; bdr = dr; }
} else {
prima[d] = r;
}
}
if (bst == -1) fout << "-1 -1\n";
else fout << bst << " " << bdr << "\n";
}
return 0;
}Greșeli frecvente
- Calculezi diferența pe săritură, nu pe prefix — cerința 1 cere diferența energiei totale (cumulate) până la acel obstacol, deci cu sume prefix, nu .
- Recalculezi fereastra de la zero — cu până la , recalcularea sumei fiecărei ferestre dă ; glisează în .
- Uiți la cerința 3 — un segment care începe de la prima săritură corespunde valorii ; dacă nu pui poziția în dicționar, pierzi astfel de segmente.