Sunteți pe pagina 1din 5

Centrul de Pregătire pentru Performanță în Informatică

Concurs de antrenament
5 februarie 2022

Descrieri ale soluțiilor

0. Produs

Rolul problemei a fost doar de acomodare cu interfața. Programul este compus doar din două
instrucțini: citirea, fin>>a>>b; și afișarea, fout<<a*b;. Era nevoie să se folosească tipul
long long pentru stocarea variabilelor.

1. Primelek

Aceasta a fost considerată problema cea mai ușoară din concurs. Pentru a obține valoarea
formată cu primele k cifre ale numărului dat, trebuia doar să eliminăm câteva cifre de la final.
Pentru a afla numărul cifrelor de eliminat era necesar ca anterior să aflăm numărul total de cifre.
Acest lucru se realizează cu un algoritm obișnuit de traversare a cifrelor unui număr. O
prezentare a acestui algoritm găsiți aici:
https://cppi.sync.ro/materia/lectii/cifrele%20unui%20num%C4%83r.pdf

2. Maxime

O primă soluție ar fi să fixăm ca poziție de început fiecare indice de la n/2+1 la n și apoi să


folosim altă repetiție pentru a afla maximul dintre toate elementele de la poziția fixată până la
finalul șirului. Această soluție (cu două repetiții una în alta) are timp de calcul de ordin n2 și nu
se încadrează în timp pe toate testele.
Pentru a obține punctajul maxim vom calcula maximele de la dreapta spre stânga. Adică, dacă
la poziția i avem deja calculat maximul dintre elementele aflate între pozițiile i și n, când
trecem la poziția i-1, maximul de acolo se obține doar comparând maximul anterior cu
elementul curent, v[i-1]. Astfel algoritmul devine liniar.

3. Cifre

O soluție care iterează prin toate numerele de k cifre nu s-ar încadra în timp.
Putem asocia fiecărui termen al sumei noastre un șir cu k elemente 0 și 1. Apoi, punem a în
dreptul cifrelor de la pozițiile pe care se află în șir 0 și b pentru celelalte poziții. Putem deci să
generăm toate submulțimile mulțimii de k elemente și apoi să construim numărul corespunzător
Centrul de Pregătire pentru Performanță în Informatică
Concurs de antrenament
5 februarie 2022

cu cifrele a și b. Descrierea unui algoritm de generare de submulțimi găsiți aici:


https://cppi.sync.ro/materia/lectii/generarea%20submultimilor.pdf.
Acest algoritm are timp de calcul de ordin 2k*k și se încadrează în timp pe toate testele (noi
avem k <= 10).
Există și o soluție foarte rapidă, care funcționează și pentru numere mai lungi, cu timp de calcul
de ordin k, care se folosește de simularea algoritmului de adunare cifră cu cifră a numerelor. Să
ne imaginăm toate cele 2k numere așezate unul sub altul și începem să adunăm cu cifra cea
mai din dreapta. Observăm că acolo avem, în total, 2k-1 cifre a și 2k-1 cifre b. Astfel, ultima cifră
a rezultatului este (a*2k-1 + b*2k-1)%10. Câtul îl păstrăm ca transport pentru adunarea
cifrelor de la penultima poziție. Observăm însă că la fiecare poziție numărul total de cifre a și b
este același, 2k-1 din fiecare. Așadar ne trebuie doar o repetiție cu k pași în care simulăm ce
tocmai am descris. Rămâne doar să acordăm atenție transportului de la ultimul calcul, care,
dacă este nenul, trebuie pus în fața rezultatului.

4. Alegere

Pentru a simplifica semnificativ problema este necesară următoarea observație: Dacă pentru o
mulțime de numere aplicăm repetat operația: alegem două numere distincte și îl înlocuim pe cel
mare cu diferența lor, până când toate numerele devin egale, valoarea comună la care se
ajunge este chiar cel mai mare divizor comun al valorilor aflate inițial în mulțime. O problemă
care folosește această idee este aici:
http://campion.edu.ro/arhiva/index.php?page=problem&action=view&id=642.
O descriere a mai multor algoritmi de calcul al celui mai mare divizor comun pentru două sau
mai multe numere se găsește aici: https://cppi.sync.ro/materia/lectii/euclid_fibonacci.pdf.
O primă soluție a problemei alegere este de a fixa fiecare poziție de început și apoi fiecare pas
posibil și să calculăm cmmdc pentru subșirului corespunzator. Această soluție nu se încadrează
în timp pe toate testele. O optimizare a sa ar fi ca, odată ce am stabilit poziția de început
(index), pasul să fie doar dintre divizorii valorii n-index.
Pentru a obține punctajul maxim, vom construi elementele mulțimilor invers, plecând de la
ultimul element, cu diverse valori ale lui pas și de fiecare dată facem cmmdc între elementul
curent și cmmdc din urmă. Fiecare loc în care ajungem cu cel puțin card salturi de la final este
o mulțime de luat în calcul. Astfel suntem pe structura unui algoritm asemănător cu ciurul lui
Eratostene (traversăm șirul dat de mai multe ori, dar de fiecare dată cu salturi de altă lungime).
Centrul de Pregătire pentru Performanță în Informatică
Concurs de antrenament
5 februarie 2022

5. Drum în matrice

Aceasta este o problemă de maxime parțiale în matrice și avem soluție cu timp de calcul de
ordin n2. Notăm cu A matricea dată. Pentru fiecare poziție (i,j) calculăm suma maximă pentru
elementele unui drum care se termină în poziția (i,j). Să o notăm D[i][j]. Pentru a respecta
restricția ca oricare două elemente de pe drum să nu fie într-o submatrice de latură L sau mai
mică, este suficient să calculăm D[i][j] în funcție de D[i-L][j] și D[i][j-L]. Pentru
elementele din submatricea cu colțul stânga sus (1,1) și colțul dreapta jos (L,L) valorile
D[i][j] se calculează ca fiind maximul elementelor din A din submatrice delimitată de (1,1) și
(i,j). În acest caz, D[i][j] = maxim(D[i-1][j], D[i][j-1], A[i][j]). Soluția
problemei este maximul dintre elementele matricei D.

6. Conex

Soluția brute force constă în simularea procesului de ștergere a nodurilor. Se va ține un vector
în care se vor marca nodurile șterse. Apoi, după fiecare nod șters, se va rula un DFS începând
dintr-un nod neșters arbitrar. Daca DFS-ul vizitează toate nodurile neșterse (bineînțeles
nevizitând noduri șterse pe parcurs), atunci răspunsul va fi "YES". Complexitate O(N*(N+M)):
vor fi N ștergeri și pentru fiecare ștergere rulăm un DFS.

Soluția eficientă se bazează pe ideea că păduri de mulțimi disjuncte se pot folosi pentru a
reprezenta componentele conexe ale unui graf, suportând operații de adăugare de muchii /
noduri. Astfel, similar cu problema bile de pe infoarena, se va inversa ordinea ștergerilor, astfel
încât ștergerile sa fie inserții. Deci fiecare pas inserează un nou nod în graf. Vom tine numărul
de componente conexe curente. O inserție a unui nod nou inițial adaugă o nouă componentă
conexă. Apoi se parcurg muchiile incidente nodului și se fac operații de join între componenta
curentă și componentele respective. Fiecare join reușit va scădea numărul de componente
conexe cu 1. Răspunsul la query va fi "YES" daca numărul de componente conexe curente la
un pas este 1. Complexitate O(N+M*log*(N)).

7. InvSub

Pentru început vom face câteva observații ajutătoare.

În primul rând, putem considera că vom alege întotdeauna să inversăm un subșir de lungime
pară. Aceasta restricție nu va afecta lungimea maximă posibilă a unui subșir crescător.
Demonstrația este imediată: dacă am inversa un subșir de lungime impară, elementul din
Centrul de Pregătire pentru Performanță în Informatică
Concurs de antrenament
5 februarie 2022

mijlocul acestui subșir va rămâne pe aceeași poziție, și am fi ajuns în aceeași situație dacă am
fi inversat subșirul fără această poziție (deci un subșir de lungime pară).

În al doilea rând, presupunem că alegem pentru a fi inversat un subșir de lungime 2k și fie 1


<= i1 < i2 < … < ik < jk < jk-1 < … < j1 <= N pozițiile din A corespunzătoare
acestui subșir. A inversa acest subșir este echivalent cu a efectua k operații de interschimbare
(swap) între perechile (i1, j1), (i2, j2), …, (ik, jk). Mai mult decât atât, aceste perechi au o
proprietatea interesantă, fiecare interval descris de o astfel de pereche este strict inclus în toate
intervalele de lungime mai mare.

Ne vine ideea sa încercăm să reducem această problemă la subprobleme mai mici. Însă cum
putem defini subprobleme care să se dovedească utile? Intuiția este următoarea: atunci când
interschimbăm perechea (i1, j1) stabilim ca toate modificările asupra șirului se fac doar în acest
interval, iar în afara lui, șirul A rămâne neschimbat.

Astfel, am putea încerca să definim o dinamică dp[i][j] := cea mai mare lungime posibilă a
unui subșir crescător care se poate obține în intervalul de poziții [i, j], aplicând cel mult o
dată operația de inversare pe subșir, în acest interval.

Această definiție nu este completă, întrucât nu avem o posibilitate directă de a ne folosi de


rezultatele pentru intervale mai scurte pentru a obține răspunsul pentru intervale mai lungi.

Extindem definiția dinamicii la: dp[i][j][first][last] := lungimea maximă a unui subșir


crescător care se poate obține aplicând o singură dată operația de inversare, considerând doar
valorile din secvența de la poziția i la poziția j, primul element al subsirului crescător este
first, iar ultimul este last.

Aceasta dinamică se calculează în ordinea crescătoare a lungimii intervalelor [i, j] după


următoarele cazuri:
● a[i] nu participă la niciun swap:
- dp[i][j][first][last] se calculează din dp[i+1][j][first][last]
- pentru dp[i][j][a[i]][last] luăm în considerare și
dp[i+1][j][ceva>=a[i]][last]+1
● a[j] nu participă la niciun swap:
- dp[i][j][first][last] se calculează din dp[i][j-1][first][last]
- pentru dp[i][j][first][a[j]] luăm în considerare și
dp[i][j-1][first][ceva<=a[j]]+1
● a[i] și a[j] participă la swap (suntem obligați să le interschimbăm între ele),
încercăm să actualizăm:
Centrul de Pregătire pentru Performanță în Informatică
Concurs de antrenament
5 februarie 2022

- dp[i][j][a[j]][last] cu dp[i+1][j-1][ceva>=a[j]][last]+1
- dp[i][j][first][a[i]] cu dp[i+1][j-1][first][ceva<=a[i]]+1
- dp[i][j][a[j]][a[i]] cu
dp[i+1][j-1][ceva>=a[j]][ceva<=a[i]]+2, doar dacă a[j]<=a[i]

Solutia o regăsim în maximul dintre valorile dinamicii pentru i=1 si j=N.

Complexitatea finală este O(N^2 * VMAX^2), unde am notat cu VMAX valoarea maximă din
șirul A. Cum N si VMAX <= 50, această complexitate se încadrează fără probleme în limitele de
timp și spațiu.

Acest editorial, precum și problemele din concurs, au fost pregătite de către:


Bogdan Iordache, Mihai Popa, Marius Nicoli.

S-ar putea să vă placă și