Prima solutie, si cea mai simpla, utilizeaza principiul programarii dinamice. Se calculeaza numarul de subsiruri din primele $i$ elemente care sunt divizibile cu un numar $j$ intre $1$ si {$1000$}. Sa notam acest numar cu {$Cnt{@[@}i{@][@}j{@]@}$}. Se obtine urmatoare recurenta pentru calculul acestor valori:
== code(cpp) |$Cnt(i, cmmdc(j, Ai)) = Cnt(i - 1, j) + Cnt(i - 1, cmmdc(j, Ai))$
== code(cpp) |Cnt[i][cmmdc(j, A[i])] = Cnt[i - 1][j] + Cnt[i - 1][cmmdc(j, A[i])]
==
Odata calculate aceste valori solutia o vom avea in {$Cnt{@[@}N{@][@}1{@]@}$}. Numerele depasesc orice tip de date predefinit si trebuie utilizate numere mari. Limitele fiind destul de mari, folosirea bazei $10$ este periculoasa, pe unele teste fiind necesar folosirea bazei $10^9^$ pentru a reduce timpul de executie. De asemenea si memoria se poate reduce, observand faptul ca pentru a calcula {$Cnt{@[@}i{@][@}j{@]@}$} ne sunt necesare doar valorile pentru {$Cnt{@[@}i-1{@][@}k{@]@}$} (ultima doua linii). Complexitatea acestei solutiei va fi $O(N * K * L)$ unde $K$ reprezinta valoarea maxima din sir si $L$ lungimea maxima a numerelor mari.
h4. Solutia 2
Cea de-a doua solutie, cu mult mai interesanta decat prima, foloseste principiul includerii se excluderii. Fie D(x) multimea numerelor din sir care sunt divizibile cu un anumit numar x, atunci numarul de submultimi formate doar din astfel de numere este Z(x) = 2^card(D(x))-1. Multimile pentru principiul includerii si excluderii sunt chiar D(p), unde p este un numar prim. Intersectia D(p1), D(p2), D(p3).. este D(p1 * p2 * p3...), oarecum evident, pentru p distincte. Rezultatul este de forma:
Cea de-a doua solutie, cu mult mai interesanta decat prima, foloseste principiul includerii se excluderii. Fie $D(x)$ multimea numerelor din sir care sunt divizibile cu un anumit numar {$x$}, atunci numarul de submultimi formate doar din astfel de numere este {$Z(x) = 2^card(D(x))^-1$}. Multimile pentru principiul includerii si excluderii sunt chiar {$D(p)$}, unde $p$ este un numar prim. Intersectia {$D(p{~1~})$}, {$D(p{~2~})$}, {$D(p{~3~})$}.. este {$D(p{~1~} * p{~2~} * p{~3~}...)$}, oarecum evident, pentru $p$ distincte. Rezultatul este de forma:
Rezultat = Z(1) - Z(2) - Z(3) - Z(5)... +
$Rezultat = Z(1) - Z(2) - Z(3) - Z(5)... +$
$Z(2 * 3) + Z(2 * 5) + Z(3 * 5)... -$
$Z(2 * 3 * 5) ...$
Z(2 * 3) + Z(2 * 5) + Z(3 * 5)... -
Acesta se deduce din principiul includerii si al excluderii. Pentru a-l calcula efectiv, luam toate numerele {$x < 1000$}, produs de numere prime distincte, si vom adauga sau scadea $Z(x)$ in functie de paritatea numarului de factori ai acestuia. Nu ne intereseaza decat produsele de numere prime distincte, care pot fi obtinute ca un produs {$p{~1~}*p{~2~}*p{~3~}$}... Complexitatea finala este sub {$O(N*K + N*L)$}, unde $K$ si $L$ au semnificatia de mai sus. Folosim $O(N*K)$ pentru a calcula $D(x)$ pentru fiecare {$x$}, dar pentru fiecare $x$ adunam sau scadem $Z(x)$ o singura data, asa ca facem doar $N$ operatii pe numere mari, o imbunatatire majora asupra primei rezolvari. Pentru a obtine aceasta complexitate este nevoie sa precalculam valorile lui $2^x^$ in {$O(N * L)$}, altfel ca sa calculam $Z(x)$ pentru fiecare ar fi nevoie de $O(L * X)$ timp.
Z(2 * 3 * 5) ...
h3. Cerere
Acesta se deduce din principiul includerii si al excluderii. Pentru a-l calcula efectiv, luam toate numerele x < 1000, produs de numere prime distincte, si vom adauga sau scadea Z(x) in functie de paritatea numarului de factori ai acestuia. Nu ne intereseaza decat produsele de numere prime distincte, care pot fi obtinute ca un produs p1*p2*p3... Complexitatea finala este sub O(N*K + N*L), unde K si L au semnificatia de mai sus. Folosim O(N*K) pentru a calcula D(x) pentru fiecare x, dar pentru fiecare x adunam sau scadem Z(x) o singura data, asa ca facem doar N operatii pe numere mari, o imbunatatire majora asupra primei rezolvari. Pentru a obtine aceasta complexitate este nevoie sa precalculam valorile lui 2^x in O(N * L), altfel ca sa calculam Z(x) pentru fiecare ar fi nevoie de O(L * X) timp.
Problema este de dificultate medie. O rezolvare $O(N*lg(N))$ este usor de gasit, fiind asemanatoare cu una deja exista in arhiva, "Stramosi":http://www.infoarena.ro/task/stramosi. Dar o astfel de rezolvare n-ar fi adus punctaj maxim in mod normal. Problema se poate rezolva printr-o simpla parcurgere in adancime din radacina implementand manual stiva DF-ului. Cand vom pune un nod $n$ pe pozitia $p$ in stiva, al {$K$}-lea stramos va fi nodul de pe pozitia $p-K$ din stiva, pentru care s-a procesat deja valoarea ceruta. Complexitatea finala a algoritmului va fi {$O(N)$}.
Cerere
Problema este de dificultate medie. O rezolvare O(N*lg(N)) este usor de gasit, fiind asemanatoare cu una deja exista in arhiva, "Stramosi". Dar o astfel de rezolvare n-ar fi adus punctaj maxim in mod normal. Problema se poate rezolva printr-o simpla parcurgere in adancime din radacina implementand manual stiva DF-ului. Cand vom pune un nod n pe pozitia p in stiva, al K-lea stramos va fi nodul de pe pozitia p-K din stiva, pentru care s-a procesat deja valoarea ceruta. Complexitatea finala a algoritmului va fi O(N).
Rubarba
h3. Rubarba
Aceasta problema e clasica in geometria computationala. O prima observatie care ne ajuta in rezolvare este ca numai punctele de pe infasuratoarea convexa influenteaza forma dreptunghiului minim. Deci primul pas in rezolvarea problemei este sa gasim infasuratoarea convexa a punctelor in O(N*lg(N)). Daca avem fixata o directie atunci e usor sa determinam in O(h) (unde h e numarul de puncte de pe infasuratoarea convexa) cele patru puncte ce marginesc dreptunghiul dupa directia aleasa si dupa directia perpendiculara. Folosind cautare binara pentru a determina cele patru puncte extreme, reducem astfel complexitatea la O(lg(h)). Observatia finala este ca un dreptunghi de arie minima ce contine o multime de puncte in interior trebuie sa aiba o latura paralela cu una din laturile infasuratorii convexe, aceasta idee este intuitiva dar demonstratia ei nu este foarte simpla. Complexitatea algoritmului ce rezolva problema poate fi O(N*lg(N) + h^2) sau O(n*lg(n) + h*lg(h)) daca folosim cautarea binara. Testele
folosite au fost generate aleator, generand aleator puncte in plan infasuratoarea convexa va avea cardinalul h teoretic egal cu Theta(lg(N)), deci rezolvarea O(N*lg(N) + h^2) ar fi luat fara probleme punctaj maxim. Mentionam ca exista o tehnica numita "Rotating Calipers" care rezolva aceasta problema si altele similare in O(N*lg(N) + h), daca vreti sa cititi despre aceasta tehnica accesati pagina [1]http://cgm.cs.mcgill.ca/~orm/rotcal.html. Idei de acolo v-ar fi ajutat sa rezolvati problema propusa recent la .campion, care cerea separarea a doua poligoane convexe cu o dreapta, si o prolema propusa anul trecut la Bursele Agora care cerea determinarea distantei maxime ce exista intre oricare doua puncte dintr-o multime, si tot pe acea pagina gasiti demonstratia matematica a faptului ca dreptunghiul de arie minima ce contine in interior o multime de puncte are o latura paralela cu o latura a infasuratorii convexe.