Pagini recente » Cod sursa (job #614838) | Cod sursa (job #979070) | Cod sursa (job #248892) | Cod sursa (job #931728) | Cod sursa (job #3322882)
/*
descrierea problemei:
N biletele puse in cerc (dupa N urmeaza 1)
pe fiecare bilet ai:
un numar x (numar de buline)
o culoare: 0 - negru, 1 - alb
x buline albe: numar +x
x buline negre: numar -x
deci transformam biletelele intr un vector circular de numere intregi v[1..N]
cerinta:
gaseste o secv circulara de biletele consecutive pe cerc cu:
suma maxima posibila
si ne mai trebuie:
S = suma maxima
P = pozitia de inceput (1-based)
L = lungimea secventei
daca exista mai multe secvente:
alegem cu P minim
si daca si P este egal, alegem cu L minim
ideea algoritmului:
citim datele:
x c
c = 1 -> v[i] = +x
c = 0 -> v[i] = -x
sum += v[i] -> suma tuturor numerelor (pentru intreg cercul)
avem un cerc -> maximum subarray circular
pe o linie (nu pe cerc) problema este clasica: subsecventa de suma maxima (SSM)
se rezolva cu Kadane in O(N)
dar aici biletele sunt in cerc:
maximum pe cerc este:
1. o secventa normala (nu trece peste capat) -> maximum subarray linie
2. o secventa care trece peste N -> 1
Kadane simplu: gasesti smax, interval [stMax..drMax]
aplici Kadane peste suma minima -> gasesti smin, interval [stMin..drMin]
calculezi sum = suma tuturor elementelor
compari:
smax (fara swap)
sum - smin (cu wrap)
si alegem varianta care da suma mai mare
!!!Obs
daca toate numerele sunt negative, Kadane-clasic da maximul (cel mai putin negaiv), dar:
smin ~ sum (subsecventa minima este aproape tot vectorul)
sum - smin = 0, dar secventa nu poate fi vida, deci nu ai voie sa iei 0
deci, in cazul "toate <= 0" trebuie sa alegi doar smax (si sa nu iei sum-smin)
pasi cod:
1.
v[] - vector de valori +x sau -x
sum - suma totala a tuturor valorilor
smax - suma maxima de secventa (liniara)
smin - suma minima de secventa
stMax, drMax - capetele secventei de suma maxima (linie)
stMin, drMin - capetele secventei de suma minima
st - inceputul secventei curente in Kadane
2. citirea si prelucrarea datelor
citesti x si t
daca t = 0 (negru), transformi x -> -x
acum v[i] este exact +x sau -x
acumulezi sum
3. Kadane pentru suma maxima (fara cerc)
s = suma secventei care se termina la i
daca e mai bine sa o extinzi, -> s += v[i]
daca nu, incepi una noua de la v[i]
daca s este mai mare decat smax, o salvezi ca solutie
4. Kadane pentru suma minima
[stMax..drMax] - subsecventa cu suma maxima (linie)
[stMin..drMin] - subsecventa cu suma minima (linie)
5. combinarea - facem din linie un cerc
avem:
suma totala sum
suma maxima liniara smax
suma minima smin
doua candidate:
fara wrap:
suma: smax
inceput: stMax
lungime: drMax - stMax + 1
cu wrap:
suma: sum - smin
inceput: drMin + 1 (urmatorul dupa secventa minima)
lungime: numarul de elemente din afara [stMin..drMin]
L = (n - drMin) + (stMin - 1)
daca smax este mai mare decat sum-smin -> alegem solutia liniara
altfel, alegi solutia pe cerc (wrap)
*/
#include <bits/stdc++.h>
using namespace std;
ifstream fin("buline.in");
ofstream fout("buline.out");
int n, v[200005], smax = INT_MIN, smin = INT_MAX, s, sum, stMax, drMax, st, stMin, drMin;
bool t;
int main()
{
fin >> n;
for (int i = 1; i <= n; i++) {
fin >> v[i] >> t;
if (!t) {
v[i] *= (-1); // valori negative pentru buline negre
}
sum += v[i]; // calculez suma totala
}
s = v[1]; // initializez suma curenta
stMax = drMax = st = 1; // pozitia secventei maxime
for (int i = 2; i <= n; i++) {
if (s + v[i] >= v[i]) { // extind secventa curenta
s += v[i];
} else { // incep o noua secventa
s = v[i];
st = i;
}
if (s > smax) { // actualizez suma maxima
smax = s;
stMax = st;
drMax = i;
}
}
// analog se face pentru suma minima
s = v[1];
stMin = st = 1;
for (int i = 2; i <= n; i++) {
if (s + v[i] <= v[i]) {
s += v[i];
} else {
s = v[i];
st = i;
}
if (s < smin) {
smin = s;
stMin = st;
drMin = i;
}
}
// comparam suma maxima obtinuta cu cea care trece prin cerc
if (smax > sum - smin) {
fout << smax << " " << stMax << " " << drMax - stMax + 1;
} else {
fout << sum - smin << " " << drMin + 1 << " " << stMin - 1 + n - drMin;
}
return 0;
}