Bac informatică 2023 Varianta 7, rezolvată

Lucrarea „2023 Varianta 7” de la Bacalaureatul la informatică, specializarea Mate-Info, limbajul C/C++: 3 subiecte, 90 de puncte și 3 ore de lucru la examen. Sub fiecare exercițiu ai răspunsul și explicația, închise până le deschizi, ca să încerci întâi singur.

Enunțurile sunt cele oficiale, publicate de Ministerul Educației pe subiecte.edu.ro. Răspunsurile și explicațiile sunt scrise de subac.

Subiectul I20 de puncte

  1. Exercițiul 14p

    Indicați numerele pe care le pot memora variabilele întregi x și y, astfel încât valoarea expresiei C/C++ alăturate să fie 1.

    y%x-(x/y)*3!=0
    • a)x=25 și y=75
    • b)x=25 și y=15
    • c)x=15 și y=0
    • d)x=10 și y=30
    Arată răspunsul și explicația

    Răspuns corect: b) x=25 și y=15

    Pentru x=25 și y=15: y%x este 15, x/y este 1, iar 15 − 1·3 = 12, diferit de 0, deci expresia are valoarea 1.

    În a) și d), y%x și x/y sunt amândouă 0, deci diferența este 0, iar c) împarte la y=0, ceea ce nu e permis.

  2. Exercițiul 24p

    Subprogramul f este definit alăturat.

    Indicați valoarea f(3,2).

    int f(int x, int y)
    {  int z;
       if (y==0) return 1;
       z=f(x,y/2);
       if (y%2!=0) return z*z*x;
       return z*z;
    }
    • a)1
    • b)2
    • c)9
    • d)18
    Arată răspunsul și explicația

    Răspuns corect: c) 9

    Funcția calculează x la puterea y prin înjumătățirea exponentului. f(3,1) folosește f(3,0) = 1 și, cum 1 este impar, returnează 1·1·3 = 3. f(3,2) folosește f(3,1) = 3 și, cum 2 este par, returnează 3·3 = 9.

  3. Exercițiul 34p

    Variabila s poate accesa un șir cu cel mult 20 de caractere.

    Indicați șirul accesat prin s în urma executării secvenței alăturate.

    strcpy(s,"2019");
    strcpy(s+3,"23");
    • a)20123
    • b)201923
    • c)202223
    • d)2023
    Arată răspunsul și explicația

    Răspuns corect: a) 20123

    După strcpy(s,"2019"), s+3 indică poziția cifrei 9. strcpy(s+3,"23") scrie de acolo „23” și terminatorul de șir, deci primele trei caractere, „201”, rămân neschimbate, iar șirul devine 20123.

  4. Exercițiul 44p

    Utilizând metoda backtracking, se generează toate parfumurile formate prin amestecarea a câte 3 esențe distincte din mulțimea {bergamotă, cireș, iris, lămâie, salcâm}. Două parfumuri sunt distincte dacă diferă prin cel puțin o esență. Primele patru soluții obținute sunt, în această ordine: (bergamotă, cireș, iris), (bergamotă, cireș, lămâie), (bergamotă, cireș, salcâm) și (bergamotă, iris, lămâie).

    Indicați penultima soluție generată.

    • a)(cireș, iris, salcâm)
    • b)(cireș, lămâie, salcâm)
    • c)(lămâie, iris, salcâm)
    • d)(iris, lămâie, salcâm)
    Arată răspunsul și explicația

    Răspuns corect: b) (cireș, lămâie, salcâm)

    Parfumurile sunt submulțimi de trei esențe, generate în ordinea din mulțime, deci ultimele încep cu esențele cele mai târzii. Ultima soluție este (iris, lămâie, salcâm), iar chiar înaintea ei vine ultima soluție care începe cu cireș: (cireș, lămâie, salcâm).

    c) nu respectă ordinea din mulțime (lămâie înaintea lui iris), deci nu este generată deloc.

  5. Exercițiul 54p

    Un graf neorientat are 5 noduri, numerotate de la 1 la 5, cu gradele figurate în tabelul alăturat.

    Indicați o pereche de valori posibile pentru x și y.

    Nod   1  2  3  4  5
    Grad  2  x  3  3  y
    • a)0 și 4
    • b)1 și 5
    • c)2 și 3
    • d)3 și 3
    Arată răspunsul și explicația

    Răspuns corect: d) 3 și 3

    Suma gradelor este dublul numărului de muchii, deci pară, iar într-un graf cu 5 noduri un grad este cel mult 4.

    b) are gradul 5; c) dă suma 2 + 2 + 3 + 3 + 3 = 13, impară; în a), nodul de grad 4 ar fi legat de toate celelalte, deci niciun nod n-ar putea avea gradul 0. Rămâne d): de exemplu, din graful complet cu 5 noduri se elimină muchiile [1,2], [1,3] și [4,5], iar gradele devin 2, 3, 3, 3, 3.

Subiectul al II-lea40 de puncte

  1. Exercițiul 1.a6p

    Algoritmul alăturat este reprezentat în pseudocod. S-a notat cu [c] partea întreagă a numărului real c.

    Scrieți valoarea afișată dacă se citesc, în această ordine, numerele 3, 746, 82, 3067, 67, 78, 178.

    citește n (număr natural nenul)
    x←0
    ┌cât timp n>0 execută
    │ citește a,b  (numere naturale)
    │ c←a; p←1
    │┌cât timp a>9 execută
    ││ a←[a/10]; p←p*10
    │└■
    │ a←a*p+b
    │┌dacă a≠c atunci
    ││ x←x+1
    │└■
    │ n←n-1
    └■
     scrie x
    Arată răspunsul și explicația

    Răspunsul din barem: 2

    2
    
    Pentru fiecare pereche (a,b), algoritmul păstrează doar prima cifră a lui a, pe poziția ei (p este puterea lui 10 corespunzătoare), și îi adaugă b; x numără perechile pentru care rezultatul diferă de a. Rezultatul este egal cu a exact când b este chiar a fără prima cifră.
    (746, 82): 700 + 82 = 782, diferit de 746; (3067, 67): 3000 + 67 = 3067, egal; (78, 178): 70 + 178 = 248, diferit de 78. Se afișează 2.
  2. Exercițiul 1.b6p

    Algoritmul alăturat este reprezentat în pseudocod. S-a notat cu [c] partea întreagă a numărului real c.

    Dacă pentru n se citește numărul 2, scrieți un șir de numere naturale din intervalul [0,9] care pot fi citite în continuare, în acea ordine, astfel încât, în urma executării algoritmului, să se afișeze valoarea 0.

    citește n (număr natural nenul)
    x←0
    ┌cât timp n>0 execută
    │ citește a,b  (numere naturale)
    │ c←a; p←1
    │┌cât timp a>9 execută
    ││ a←[a/10]; p←p*10
    │└■
    │ a←a*p+b
    │┌dacă a≠c atunci
    ││ x←x+1
    │└■
    │ n←n-1
    └■
     scrie x
    Arată răspunsul și explicația
    Exemplu: 5 0 7 0
    
    Pentru un număr a de o cifră, p rămâne 1, iar rezultatul este a + b, egal cu a doar dacă b = 0. Cu n=2 se citesc două perechi, deci șirul are forma x, 0, y, 0, cu x și y din intervalul [0,9].
  3. Exercițiul 1.c10p

    Algoritmul alăturat este reprezentat în pseudocod. S-a notat cu [c] partea întreagă a numărului real c.

    Scrieți programul C/C++ corespunzător algoritmului dat.

    citește n (număr natural nenul)
    x←0
    ┌cât timp n>0 execută
    │ citește a,b  (numere naturale)
    │ c←a; p←1
    │┌cât timp a>9 execută
    ││ a←[a/10]; p←p*10
    │└■
    │ a←a*p+b
    │┌dacă a≠c atunci
    ││ x←x+1
    │└■
    │ n←n-1
    └■
     scrie x
    Arată răspunsul și explicația
    #include <iostream>
    using namespace std;
    
    int main()
    {
        int n, x = 0, a, b, c, p;
        cin >> n;
        while (n > 0)
        {
            cin >> a >> b;
            c = a;
            p = 1;
            while (a > 9)
            {
                a = a / 10;
                p = p * 10;
            }
            a = a * p + b;
            if (a != c) x = x + 1;
            n = n - 1;
        }
        cout << x;
        return 0;
    }
    
    Cele două structuri cât timp devin while, iar [a/10] este împărțirea întreagă din C/C++. a și b se citesc la fiecare pas al buclei exterioare, ca în algoritm.
  4. Exercițiul 1.d6p

    Algoritmul alăturat este reprezentat în pseudocod. S-a notat cu [c] partea întreagă a numărului real c.

    Scrieți în pseudocod un algoritm, echivalent cu cel dat, înlocuind prima structură cât timp...execută cu o structură repetitivă de tip pentru...execută.

    citește n (număr natural nenul)
    x←0
    ┌cât timp n>0 execută
    │ citește a,b  (numere naturale)
    │ c←a; p←1
    │┌cât timp a>9 execută
    ││ a←[a/10]; p←p*10
    │└■
    │ a←a*p+b
    │┌dacă a≠c atunci
    ││ x←x+1
    │└■
    │ n←n-1
    └■
     scrie x
    Arată răspunsul și explicația
    citește n (număr natural nenul)
    x←0
    ┌pentru i←1,n execută
    │ citește a,b (numere naturale)
    │ c←a; p←1
    │┌cât timp a>9 execută
    ││ a←[a/10]; p←p*10
    │└■
    │ a←a*p+b
    │┌dacă a≠c atunci
    ││ x←x+1
    │└■
    └■
    scrie x
    
    n era folosit doar ca un contor care scade până la 0, deci bucla se executa de n ori. Structura pentru, cu un contor nou i de la 1 la n, face același număr de pași, iar instrucțiunea n←n-1 dispare.
  5. Exercițiul 26p

    Într-un arbore cu rădăcină un nod se află pe nivelul x dacă lanțul elementar care are o extremitate în nodul respectiv și cealaltă extremitate în rădăcina arborelui are lungimea x. Pe nivelul 0 se află un singur nod (rădăcina).

    Un arbore cu 6 noduri, numerotate de la 1 la 6, are muchiile:

    1. [1,2]
    2. [2,3]
    3. [2,6]
    4. [3,4]
    5. [3,5]

    Scrieți nodurile care pot fi desemnate ca rădăcină, astfel încât fiecare dintre arborii obținuți să aibă un număr minim de niveluri.

    Arată răspunsul și explicația

    Răspunsul din barem: 2, 3

    2, 3
    
    Numărul de niveluri este cel mai mic atunci când rădăcina este cât mai la mijlocul arborelui. Cu rădăcina 2, nodurile cele mai îndepărtate (4 și 5) sunt la distanța 2, deci arborele are 3 niveluri; la fel cu rădăcina 3, pentru care cele mai îndepărtate sunt 1 și 6. Orice altă rădăcină are un nod la distanța 3 sau mai mare (de exemplu, din 1 până la 4), deci cel puțin 4 niveluri.
  6. Exercițiul 36p

    Variabila p, declarată alăturat, memorează caracteristicile unui produs: denumire și preț.

    Scrieți o secvență de instrucțiuni C/C++ prin care variabila a memorează valoarea primei litere a denumirii produsului respectiv, dacă acesta are prețul strict mai mic decât 100, sau caracterul * în caz contrar.

    struct produs
    {  char denumire[20];
       int pret;
    }p;
    char a;
    Arată răspunsul și explicația
    if (p.pret < 100) a = p.denumire[0];
    else a = '*';
    
    Prima literă a denumirii este primul caracter al șirului, p.denumire[0]. Caracterul * se scrie între apostrofuri, ca o constantă de tip caracter.

Subiectul al III-lea30 de puncte

  1. Exercițiul 110p

    Subprogramul DNPI are un singur parametru, n, prin care primește un număr natural (n∈[1,109]), și afișează pe ecran, separați prin câte un spațiu, toți divizorii pozitivi impari ai lui n care NU sunt primi.

    Scrieți definiția completă a subprogramului.

    Exemplu: dacă n=90, se afișează pe ecran, nu neapărat în această ordine, numerele

    1 9 15 45
    Arată răspunsul și explicația
    void DNPI(int n)
    {
        int d, v, k, t, prim;
        for (d = 1; d * d <= n; d++)
            if (n % d == 0)
                for (t = 1; t <= 2; t++)
                {
                    if (t == 1) v = d;
                    else v = n / d;
                    if (t == 2 && v == d) break;
                    if (v % 2 == 1)
                    {
                        prim = 1;
                        if (v < 2) prim = 0;
                        for (k = 2; k * k <= v; k++)
                            if (v % k == 0) prim = 0;
                        if (prim == 0) cout << v << ' ';
                    }
                }
    }
    
    Divizorii lui n se iau în perechi, d și n/d, cu d până la radicalul lui n (când d = n/d, divizorul se ia o singură dată). Pentru fiecare divizor impar se verifică dacă este prim; 1 nu este prim, deci se afișează și el. Enunțul acceptă numerele în orice ordine.
  2. Exercițiul 210p

    Un joc folosește o tablă dreptunghiulară, pe care sunt reprezentate celule de dimensiune egală, dispuse pe m linii și pe n coloane. În fiecare celulă este înscris un număr natural.

    Numim pătrat de valoare p patru celule ale tablei, situate pe două linii consecutive și pe două coloane consecutive, cu proprietatea că suma valorilor înscrise în aceste celule este egală cu p. Scopul jocului este determinarea unui pătrat de valoare maximă.

    Scrieți un program C/C++ care citește de la tastatură două numere naturale din intervalul [2,20], m și n, apoi elementele unui tablou bidimensional cu m linii și n coloane, numere naturale din intervalul [0,104], reprezentând numerele înscrise pe tabla de joc, în ordinea dispunerii celulelor corespunzătoare. Programul determină un pătrat de valoare maximă al tablei și afișează pe ecran această valoare.

    Exemplu: pentru m=5, n=4 și tabloul alăturat, se afișează pe ecran valoarea 36, corespunzătoare pătratului evidențiat în figură.

    11230
    31012
    113121
    1231
    71201
    Arată răspunsul și explicația
    #include <iostream>
    using namespace std;
    
    int main()
    {
        int m, n, a[20][20], i, j, s, maxim = -1;
        cin >> m >> n;
        for (i = 0; i < m; i++)
            for (j = 0; j < n; j++)
                cin >> a[i][j];
        for (i = 0; i + 1 < m; i++)
            for (j = 0; j + 1 < n; j++)
            {
                s = a[i][j] + a[i][j + 1] + a[i + 1][j] + a[i + 1][j + 1];
                if (s > maxim) maxim = s;
            }
        cout << maxim;
        return 0;
    }
    
    Un pătrat este determinat de celula lui din stânga-sus, (i,j), care poate fi pe orice linie în afară de ultima și pe orice coloană în afară de ultima. Pentru fiecare se calculează suma celor patru celule și se reține cea mai mare. Valorile sunt naturale, deci maxim poate porni de la -1.
  3. Exercițiul 3.a2p

    Fișierul date.in conține pe prima linie două numere naturale din intervalul [1,106], m și n, iar pe următoarele două linii numere naturale din intervalul [0,102): pe a doua linie un șir A, de m numere, iar pe a treia linie un șir B, de n numere. Numerele aflate pe aceeași linie sunt separate prin câte un spațiu. Se cere să se afișeze pe ecran numărul maxim de perechi de forma (pa,pb) (pa∈[1,m], pb∈[1,n]), cu proprietatea că termenul de pe poziția pa din șirul A are aceeași valoare cu termenul de pe poziția pb din șirul B și că fiecare poziție, corespunzătoare șirului A, respectiv șirului B, apare în cel mult o pereche, ca în exemplu. Proiectați un algoritm eficient din punctul de vedere al timpului de executare.

    Exemplu: dacă fișierul conține numerele alăturate, se afișează pe ecran 6 (de exemplu, pentru perechile (1,1), (2,9), (4,2), (5,5), (6,6), (7,7) sau pentru perechile (1,2), (2,9), (4,1), (5,7), (6,8), (8,5)).

    8 9
    1 0 4 1 5 3 5 5
    1 1 1 7 5 3 5 3 0

    Descrieți în limbaj natural algoritmul proiectat, justificând eficiența acestuia.

    Arată răspunsul și explicația
    Fiecare poziție poate apărea în cel mult o pereche, iar o pereche leagă doi termeni egali. Pentru o valoare v care apare de a ori în A și de b ori în B se pot forma cel mult min(a, b) perechi cu valoarea v, și chiar atâtea. Răspunsul este suma acestor minime, pentru toate valorile.
    
    Valorile sunt între 0 și 99, deci se folosesc doi vectori de frecvență cu câte 100 de elemente: pe măsura citirii lui A crește fa[v], iar pe măsura citirii lui B crește fb[v]. La final se adună min(fa[v], fb[v]) pentru v de la 0 la 99.
    
    Eficiență: fiecare număr se citește și se numără o singură dată, în timp constant, iar suma finală are un număr fix de pași, deci timpul este liniar în numărul de valori din fișier.
  4. Exercițiul 3.b8p

    Fișierul date.in conține pe prima linie două numere naturale din intervalul [1,106], m și n, iar pe următoarele două linii numere naturale din intervalul [0,102): pe a doua linie un șir A, de m numere, iar pe a treia linie un șir B, de n numere. Numerele aflate pe aceeași linie sunt separate prin câte un spațiu. Se cere să se afișeze pe ecran numărul maxim de perechi de forma (pa,pb) (pa∈[1,m], pb∈[1,n]), cu proprietatea că termenul de pe poziția pa din șirul A are aceeași valoare cu termenul de pe poziția pb din șirul B și că fiecare poziție, corespunzătoare șirului A, respectiv șirului B, apare în cel mult o pereche, ca în exemplu. Proiectați un algoritm eficient din punctul de vedere al timpului de executare.

    Exemplu: dacă fișierul conține numerele alăturate, se afișează pe ecran 6 (de exemplu, pentru perechile (1,1), (2,9), (4,2), (5,5), (6,6), (7,7) sau pentru perechile (1,2), (2,9), (4,1), (5,7), (6,8), (8,5)).

    8 9
    1 0 4 1 5 3 5 5
    1 1 1 7 5 3 5 3 0

    Scrieți programul C/C++ corespunzător algoritmului proiectat.

    Arată răspunsul și explicația
    #include <fstream>
    #include <iostream>
    using namespace std;
    
    int main()
    {
        ifstream fin("date.in");
        int fa[100] = {0}, fb[100] = {0}, m, n, i, v, nr = 0;
        fin >> m >> n;
        for (i = 0; i < m; i++)
        {
            fin >> v;
            fa[v]++;
        }
        for (i = 0; i < n; i++)
        {
            fin >> v;
            fb[v]++;
        }
        fin.close();
        for (v = 0; v < 100; v++)
            if (fa[v] < fb[v]) nr = nr + fa[v];
            else nr = nr + fb[v];
        cout << nr;
        return 0;
    }
    
    Programul face pașii de la 3.a. Numărul perechilor este cel mult 10^6 și încape în tipul int.

Vrei să vezi cât ai lua?

În test ai cronometrul de la examen, codul tău se compilează pe loc, iar la final primești nota.

Rezolv-o cu timpul de la examen