Hezov

Q21 Unibuc cu explicatii

Dec 17th, 2024 (edited)
27
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 4.47 KB | None | 0 0
  1. #include <iostream>
  2. #include <set>
  3. using namespace std;
  4. set<long long> S;
  5. long long frecv[4], v[] = {3,4,5,8,10,12,14,32,57,64};
  6. /** Codificare :
  7.     0 - nu folosim,
  8.     1 - face parte din latura a
  9.     2 - face parte din latura b
  10.     3 - face parte din latura c
  11.  
  12.     in frecv[i] vom retine suma tuturor numerelor
  13.     ce adunate formeaza o latura din triunghi.
  14. */
  15.  
  16. /** Putem folosi baza 4 pentru a
  17.     parcurge toate posibilitatile.
  18.     0 0 0 0 0 0 0 0 0 0
  19.     1 0 0 0 0 0 0 0 0 0
  20.     2 0 0 0 0 0 0 0 0 0
  21.     3 0 0 0 0 0 0 0 0 0
  22.     0 1 0 0 0 0 0 0 0 0
  23.     ...
  24.     3 3 3 3 3 3 3 3 3 3
  25.  
  26.     Pentru fiecare element din v[]
  27.     ii corespunde pozitia cifrei din
  28.     reprezentarea in baza 4.
  29. */
  30.  
  31. /**
  32.  
  33.     Folosind 2 biti putem reprezenta o cifra din baza 4 :
  34.     0 (4) -> 00 (2)
  35.     1 (4) -> 01 (2)
  36.     2 (4) -> 10 (2)
  37.     3 (4) -> 11 (2)
  38. */
  39.  
  40.  
  41. /**
  42.     Pentru a obtine ultimii 2 biti putem folosi
  43.     (n % 4) sau (n & 3) (sunt echivalente)
  44.    
  45.     Putem imparti la 2^n folosind (1 >> n)
  46.     si implicit prin 4^n folosind (1 >> (2*n))
  47.    
  48.     Consideram ca cifrele din baza 4 sunt notate astfel :
  49.     _ _ _ _ _ _ _ _ _ _
  50.     0 1 2 3 4 5 6 7 8 9
  51.     Asadar putem afla cifra x din reprezentarea in baza 4 a lui i astfel :
  52.     (i >> (2 * x)) % 4 .
  53.     Adica mai intai impartim i prin 4^x si apoi luam ultimii 2 biti.
  54.    
  55.     (La fel cum in baza 10 impartind prin 10^x taiem ultimele x cifre din baza 10,
  56.     impartind prin 4^x taiem ultimele x cifre din baza 4).
  57.    
  58. */
  59. int main()
  60. {
  61.     for(int i = 0;i<(1<<20);i++)
  62.     {
  63.         /// i este numarul pe care il descompunem in baza 4.
  64.  
  65.         ///resetam valorile din frecv.
  66.         for(int j = 0;j<4;j++)
  67.             frecv[j] = 0;
  68.         /// pe baza descompunerii in baza 4 adunam unde trebuie v[j].
  69.         for(int j = 0;j<10;j++)
  70.         {
  71.             int nrelem = ((i >> (2*j)) % 4);
  72.             frecv[nrelem] += v[j];
  73.         }
  74.         /**
  75.         Conditia (1) :
  76.         Intr-un triunghi se respecta mereu relatia
  77.         a < b + c (unde a,b,c sunt lungimile laturilor.)
  78.  
  79.  
  80.         Acum verificam daca aria este
  81.         valida folosind formula lui Heron.
  82.         Aria = sqrt(p*(p-a)*(p-b)*(p-c)) , unde p = (a+b+c)/2
  83.  
  84.         Scapam de radical, ridicand la puterea a doua.
  85.         Aria^2 = p*(p-a)*(p-b)*(p-c).
  86.  
  87.  
  88.         p poate avea virgula (.5) deci trebuie sa facem o modificare a formulei
  89.         si sa transformam p in 2*p in fiecare factor.
  90.         Aria^2 * ceva = 2 * p * 2 ( p - a ) * 2 * (p - b) * 2 * (p - c)
  91.         Evident acest "ceva" va fi 2 * 2 * 2 * 2 = 16
  92.         Aria^2 * 16 = 2p *(2p - 2a) * (2p - 2b) * (2p - 2c).
  93.  
  94.         ... Am scapat astfel de problema virgulei.
  95.  
  96.         Conditia (2) :
  97.         Trebuie sa ne asiguram ca factorii ( 2p - 2a) , (2p - 2b), (2p - 2c) sunt toti pozitivi
  98.         (In cod 2p va fi P = a + b + c.)
  99.         */
  100.  
  101.         long long P = frecv[1] + frecv[2] + frecv[3];
  102.         bool valid = true;
  103.         /// Verificam pe rand cele doua conditii.
  104.         // metoda 1  : if-uri
  105.         /*
  106.         if(frecv[1] >= frecv[2] + frecv[3]) valid = false;
  107.         if(frecv[2] >= frecv[1] + frecv[3]) valid = false;
  108.         if(frecv[3] >= frecv[1] + frecv[2]) valid = false;
  109.         if(P - 2*frecv[1] <= 0) valid = false;
  110.         if(P - 2*frecv[2] <= 0) valid = false;
  111.         if(P - 2*frecv[3] <= 0) valid = false;
  112.         */
  113.  
  114.         // metoda 2 : for - cu termeni generali
  115.         /*
  116.              n % 3 = {0,1,2}.
  117.              n % 3 + 1 = {1,2,3}.
  118.              si atunci in loc de (n) putem inlocui cu (n+1) si (n+2)
  119.              pentru a obtine ceilalti doi termeni din multimea {1,2,3}.
  120.  
  121.              Spre exemplu, daca avem j = 2 :
  122.              (2 % 3) + 1 = 3 (n)
  123.              ((2+1) % 3) + 1 = 1 (n+1)
  124.              ((2+2) % 3) + 1 = 2  (n+2)
  125.  
  126.         */
  127.         for(int j = 0; j < 3 && valid; j++)
  128.         {
  129.             /// Conditia 1 :
  130.             if(frecv[j % 3 + 1] >= frecv[(j+1) % 3 + 1] + frecv[(j+2) % 3 + 1])
  131.                valid = false;
  132.             /// Conditia 2 :
  133.             if(P - 2 * frecv[j + 1] <= 0) /// (j + 1) - > {1, 2, 3}
  134.                valid = false;
  135.         }
  136.         /// Daca avem o arie valida o calculam si o punem in set.
  137.         if(valid)
  138.         {
  139.            /// Acum de fapt calculam (aria^2 * 16) .. dupa cele explicate mai sus.
  140.            long long aria = P * (P - 2*frecv[1]) * (P - 2*frecv[2]) * (P - 2*frecv[3]);
  141.            S.insert(aria);
  142.  
  143.         }
  144.  
  145.     }
  146.     cout << S.size() << '\n';
  147.     return 0;
  148. }
  149.  
Add Comment
Please, Sign In to add comment