Differences

This shows you the differences between two versions of the page.

Link to this comparison view

pa:laboratoare:laborator-02 [2026/03/13 07:01]
gabriel.gutu Updated wording: "Înmulțirea este asociativă"
pa:laboratoare:laborator-02 [2026/03/15 19:10] (current)
aureliu.antonie [Gardurile lui Gigel]
Line 359: Line 359:
     * $dp[i] = (dp[i-1] + dp[i-4]) \ \% \  MOD$      * $dp[i] = (dp[i-1] + dp[i-4]) \ \% \  MOD$ 
     *      * 
-<​note>​ Așa cum am zis în secțiunea de [[http://​ocw.cs.pub.ro/​courses/​pa/​laboratoare/​laborator-04?&#​sfaturireguli|sfaturi și reguli]] vrem să facem o **parționare** după un anumit **criteriu**:​ în cazul problemei de față, criteriul de parționare este dacă gardul se termină cu o scândură verticală sau orizontală.+<​note>​ Așa cum am zis în secțiunea de [[http://​ocw.cs.pub.ro/​courses/​pa/​laboratoare/​laborator-02?&#​sfaturireguli|sfaturi și reguli]] vrem să facem o **parționare** după un anumit **criteriu**:​ în cazul problemei de față, criteriul de parționare este dacă gardul se termină cu o scândură verticală sau orizontală.
  
  
-De asemenea, tot în secțiunea [[http://​ocw.cs.pub.ro/​courses/​pa/​laboratoare/​laborator-04?&#​sfaturireguli|sfaturi și reguli]] am precizat că nu vrem **să număram un obiect** (un mod de a construi gardul) **de două ori**. Recurența noastră (dp[i] = dp[i-1] + dp[i-4]) nu ia un obiect de două ori pentru că orice soluție care vine din dp[i-4] e diferită de alta care vine din dp[i-1] pentru că diferă în cel puțin ultima scândură așezată) </​note> ​+De asemenea, tot în secțiunea [[http://​ocw.cs.pub.ro/​courses/​pa/​laboratoare/​laborator-02?&#​sfaturireguli|sfaturi și reguli]] am precizat că nu vrem **să număram un obiect** (un mod de a construi gardul) **de două ori**. Recurența noastră (dp[i] = dp[i-1] + dp[i-4]) nu ia un obiect de două ori pentru că orice soluție care vine din dp[i-4] e diferită de alta care vine din dp[i-1] pentru că diferă în cel puțin ultima scândură așezată) </​note> ​
  
 == Implementare recurență == == Implementare recurență ==
Line 409: Line 409:
 De multe ori, este nevoie să folosim câteva tehnici pentru a obține performanța maximă cu recurența găsită. De multe ori, este nevoie să folosim câteva tehnici pentru a obține performanța maximă cu recurența găsită.
  
-În prima parte a laboratorului ​se menționa tehnica de memoizare. În acesta, ne vom rezuma la cum putem folosi cunoștințele de lucru matriceal pentru a favoriza implementarea unor anumite tipuri de recurențe.+În prima parte a [[pa:​laboratoare:​laborator-01|laboratorului ​01]] se menționa tehnica de **memoizare**. În acesta, ne vom rezuma la cum putem folosi cunoștințele de lucru matriceal pentru a favoriza implementarea unor anumite tipuri de recurențe.
  
 ==== Exponențiere pe matrice pentru recurențe liniare ==== ==== Exponențiere pe matrice pentru recurențe liniare ====
Line 498: Line 498:
 $$S_i = S_{k}C^{i -k}$$ $$S_i = S_{k}C^{i -k}$$
  
 +Pentru a aduce un plus de viteză, vom folosi un truc numit [[https://​en.wikipedia.org/​wiki/​Exponentiation_by_squaring|exponențiere rapidă]]. Pe scurt, vom ridica o valoare(notată $a$) la puterea n, împărțind ​ n folosind reprezentarea sa binară.
  
-În laboratorul ​2 (Divide et Imperaam învățat că putem calcula $^ n$ în timp logaritmic. Deoarece ​și înmulțirea matricilor ​este asociativă, putem calcula $n$ in timp logaritmic.+De exemplu, dacă am vrea să calculăm:​ 
 +$$ 5^{13} = 5^{1101_2}= 5^8 * 5^4 * 5^1 $$ 
 + 
 +Exponentul are exact $\lfloor log_2(n) \rfloor + 1$ cifre în baza 2, deci vom avea nevoie de $O(log(n))$ înmulțiri, fiind condiționați de faptul ​că trebuie să cunoaștem $a^1, a^2, a^4, etc.$ Din fericire, ​putem calcula ​rapid acești factori prin ridicarea la pătrat a elementului precedent. 
 + 
 +În final, putem implementa un algoritm iterativ pentru calcularea rezultatului ​$a^n$ iterând prin cifrele din baza 2 ale lui n și înmulțind cu ${a^2}^{k}$ atunci când cifra curentă ​este 1(pentru viteză, vom folosi operații pe biți în loc de o iterare propriu zisă prin cifre). 
 + 
 +Mai jos putem vedea o implementare in C++: 
 +<code cpp> 
 +long long pow(long long a, long long n) { 
 +    long long res = 1; 
 +    while (n > 0) { 
 +        // daca cel mai nesemnificativ bit(LSB) din n este 1 
 +        if (n & 1) { 
 +            res = res * a; 
 +        } 
 +         
 +        // calculam urmatorul factor 
 +        a = a * a; 
 +         
 +        // shiftam la dreapta n cu o pozitie(urmatorul bit va deveni LSB) 
 +        n >>= 1; 
 +    } 
 +    return res; 
 +
 +</​code>​ 
 + 
 +Acest truc poate fi folosit pentru orice tip de date pentru care înmulțirea este asociativă(inclusiv matrice).
  
 Obținem astfel o soluție cu următoarele complexități:​ Obținem astfel o soluție cu următoarele complexități:​
pa/laboratoare/laborator-02.1773378072.txt.gz · Last modified: 2026/03/13 07:01 by gabriel.gutu
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0