Bac informatică 2024 Varianta 8, rezolvată

Lucrarea „2024 Varianta 8” 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

    Variabilele x și y memorează câte un număr natural (x≤y).

    Indicați expresia C/C++ cu valoarea 1 dacă și numai dacă intervalul [x,y] NU conține niciun număr de două cifre.

    • a)!(x>=10 || y>99)
    • b)!(x<=99 && y>=10)
    • c)x>=10 || y<=99
    • d)x>99 && y<10
    Arată răspunsul și explicația

    Răspuns corect: b) !(x<=99 && y>=10)

    Intervalul [x,y] conține un număr de două cifre exact când se suprapune cu [10,99], adică x<=99 && y>=10. Negația acestei condiții este varianta b).

    a) este adevărată, de exemplu, pentru [5,50], care conține numere de două cifre; c) este adevărată tot pentru [5,50]; d) nu poate fi adevărată niciodată, pentru că x≤y.

  2. Exercițiul 24p

    Subprogramul f este definit alăturat.

    Indicați un apel în urma căruia se afișează pe ecran secvența:

    13579

    void f(int x,int y,int z)
    { if(z<x)
       { cout<<y; | printf("%d",y);
         f(x,y+2,z+1);
       }
    }
    • a)f(5,0,0);
    • b)f(5,1,1);
    • c)f(6,1,6);
    • d)f(6,1,1);
    Arată răspunsul și explicația

    Răspuns corect: d) f(6,1,1);

    Fiecare apel cu z<x afișează y și continuă cu y mai mare cu 2 și z mai mare cu 1. Se afișează deci y, y+2, y+4, … de x−z ori.

    Pentru 13579 trebuie să se înceapă de la 1 și să se afișeze 5 valori: y=1 și x−z=5, adică f(6,1,1). a) începe de la 0, b) afișează doar patru valori, iar c) nu afișează nimic.

  3. Exercițiul 34p

    Variabilele s, x și y permit memorarea câte unui șir de cel mult 15 caractere.

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

    strcpy(x,"soare");
    strcpy(y,"ploaie");
    if (strcmp(x,y)>0) strcpy(s,x+1);
    else strcpy(s,y+2);
    • a)oare
    • b)oaie
    • c)ploaie
    • d)soare
    Arată răspunsul și explicația

    Răspuns corect: a) oare

    strcmp(x,y) compară șirurile alfabetic, literă cu literă: „soare” începe cu s, care vine după p, deci este mai mare decât „ploaie” și rezultatul este pozitiv.

    Se execută strcpy(s,x+1), care copiază șirul x începând cu a doua literă: oare.

  4. Exercițiul 44p

    Un arbore cu 14 noduri, numerotate de la 1 la 14, este reprezentat prin vectorul de “tați” (13,3,0,6,13,3,3,7,6,2,13,2,6,13).

    Indicați nodul care este rădăcina arborelui.

    • a)1
    • b)3
    • c)7
    • d)13
    Arată răspunsul și explicația

    Răspuns corect: b) 3

    În vectorul de tați, rădăcina este singurul nod care nu are tată, adică cel pentru care valoarea din vector este 0. Valoarea 0 se află pe poziția 3, deci rădăcina este nodul 3.

  5. Exercițiul 54p

    Indicați numărul maxim de vârfuri izolate pe care le poate avea un graf orientat cu 24 de vârfuri și 24 de arce poziționate adecvat.

    • a)5
    • b)6
    • c)18
    • d)21
    Arată răspunsul și explicația

    Răspuns corect: c) 18

    Ca să rămână cât mai multe vârfuri izolate, arcele se pun între cât mai puține vârfuri. Între k vârfuri pot exista cel mult k·(k−1) arce, câte unul în fiecare sens pentru fiecare pereche.

    5 vârfuri permit doar 20 de arce, prea puține, dar 6 vârfuri permit 30, suficient pentru 24. Rămân izolate 24 − 6 = 18 vârfuri.

Subiectul al II-lea40 de puncte

  1. Exercițiul 1.a6p

    Algoritmul alăturat este reprezentat în pseudocod.

    S-a notat cu a%b restul împărțirii numărului natural a la numărul natural nenul b și cu [c] partea întreagă a numărului real c.

    Scrieți valoarea afișată în urma executării algoritmului dacă se citește numărul 412531.

     citește n
      (număr natural nenul)
     x ← -1; y ← -1
    ┌cât timp n>9 execută
    │┌dacă x=-1 atunci x←n%100
    ││altfel y←n%100
    │└■
    │ n←[n/10]
    └■
    ┌dacă x<y atunci n←(n*100+x)*100+y
    │altfel n←(n*100+y)*100+x
    └■
    scrie n
    Arată răspunsul și explicația

    Răspunsul din barem: 43141

    43141
    
    La prima trecere prin buclă, x primește ultimele două cifre ale numărului; la fiecare trecere următoare, y primește ultimele două cifre ale valorii curente, deci la final y conține primele două cifre. Bucla se oprește când rămâne prima cifră. Rezultatul alipește prima cifră și cele două perechi, cea mai mică dintre ele înaintea celeilalte.
    Pentru 412531: x = 31, y = 41, iar n rămâne 4. Cum 31 < 41, n devine (4·100+31)·100+41 = 43141.
  2. Exercițiul 1.b6p

    Algoritmul alăturat este reprezentat în pseudocod.

    S-a notat cu a%b restul împărțirii numărului natural a la numărul natural nenul b și cu [c] partea întreagă a numărului real c.

    Scrieți două numere din intervalul [1,11110] care pot fi citite pentru variabila n, astfel încât, pentru fiecare dintre acestea, în urma executării algoritmului, să se afișeze valoarea 11111.

     citește n
      (număr natural nenul)
     x ← -1; y ← -1
    ┌cât timp n>9 execută
    │┌dacă x=-1 atunci x←n%100
    ││altfel y←n%100
    │└■
    │ n←[n/10]
    └■
    ┌dacă x<y atunci n←(n*100+x)*100+y
    │altfel n←(n*100+y)*100+x
    └■
    scrie n
    Arată răspunsul și explicația
    Exemplu: 111 1111
    
    Rezultatul este prima cifră, urmată de cea mai mică și apoi de cea mai mare dintre perechile x (ultimele două cifre) și y (primele două cifre). Ca să iasă 11111, prima cifră trebuie să fie 1, iar ambele perechi 11. Din intervalul [1,11110], asta se întâmplă pentru 111, 1111 și 11011.
  3. Exercițiul 1.c10p

    Algoritmul alăturat este reprezentat în pseudocod.

    S-a notat cu a%b restul împărțirii numărului natural a la numărul natural nenul b și 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 ← -1; y ← -1
    ┌cât timp n>9 execută
    │┌dacă x=-1 atunci x←n%100
    ││altfel y←n%100
    │└■
    │ n←[n/10]
    └■
    ┌dacă x<y atunci n←(n*100+x)*100+y
    │altfel n←(n*100+y)*100+x
    └■
    scrie n
    Arată răspunsul și explicația
    #include <iostream>
    using namespace std;
    
    int main()
    {
        int n, x = -1, y = -1;
        cin >> n;
        while (n > 9)
        {
            if (x == -1) x = n % 100;
            else y = n % 100;
            n = n / 10;
        }
        if (x < y) n = (n * 100 + x) * 100 + y;
        else n = (n * 100 + y) * 100 + x;
        cout << n;
        return 0;
    }
    
    cât timp devine while, iar [n/10] este împărțirea întreagă din C/C++.
  4. Exercițiul 1.d6p

    Algoritmul alăturat este reprezentat în pseudocod.

    S-a notat cu a%b restul împărțirii numărului natural a la numărul natural nenul b și cu [c] partea întreagă a numărului real c.

    Scrieți în pseudocod un algoritm echivalent cu cel dat, înlocuind adecvat structura cât timp...execută cu o structură repetitivă cu test final.

     citește n
      (număr natural nenul)
     x ← -1; y ← -1
    ┌cât timp n>9 execută
    │┌dacă x=-1 atunci x←n%100
    ││altfel y←n%100
    │└■
    │ n←[n/10]
    └■
    ┌dacă x<y atunci n←(n*100+x)*100+y
    │altfel n←(n*100+y)*100+x
    └■
    scrie n
    Arată răspunsul și explicația
    citește n (număr natural nenul)
    x←-1; y←-1
    ┌dacă n>9 atunci
    │┌repetă
    ││┌dacă x=-1 atunci x←n%100
    │││altfel y←n%100
    ││└■
    ││ n←[n/10]
    │└până când n≤9
    └■
    ┌dacă x<y atunci n←(n*100+x)*100+y
    │altfel n←(n*100+y)*100+x
    └■
    scrie n
    
    repetă…până când execută corpul cel puțin o dată, iar cât timp poate să nu îl execute deloc: pentru un n de o cifră, bucla dată nu se execută. De aceea structura cu test final este pusă sub condiția n>9. Condiția de oprire este negata celei de continuare: n≤9.
  5. Exercițiul 26p

    Utilizând metoda backtracking, se generează toate buchetele formate din câte trei flori distincte din mulțimea ordonată astfel: {trandafir, crin, gerbera, iris, eustoma, orhidee, zambilă}; în același buchet crinul nu poate fi împreună cu eustoma sau cu zambila. Două buchete diferă prin cel puțin o floare. Primele cinci soluții sunt, în ordinea generării:

    1. (trandafir, crin, gerbera)
    2. (trandafir, crin, iris)
    3. (trandafir, crin, orhidee)
    4. (trandafir, gerbera, iris)
    5. (trandafir, gerbera, eustoma)

    Scrieți două soluții, una generată imediat înainte, iar cealaltă generată imediat după (crin, gerbera, orhidee).

    Arată răspunsul și explicația

    Răspunsul din barem: (crin, gerbera, iris) (crin, iris, orhidee)

    (crin, gerbera, iris) (crin, iris, orhidee)
    
    Buchetele se generează ca submulțimi de trei flori, în ordinea din mulțime, iar crinul nu apare împreună cu eustoma sau zambila.
    Înainte de (crin, gerbera, orhidee): cu (crin, gerbera) pe primele poziții, floarea de dinaintea orhideei care se poate folosi este irisul, pentru că eustoma nu poate sta cu crinul. După el: după orhidee ar urma zambila, interzisă cu crinul, deci se schimbă a doua floare, gerbera, cu următoarea, irisul, iar a treia devine cea mai mică floare de după el care se poate folosi, orhideea.
  6. Exercițiul 36p

    Gama muzicală conține, în această ordine, notele do, re, mi, fa, sol, la, si. Două note formează un interval muzical, iar acesta este numit terță dacă, în ordinea din gamă, între cele două note există o singură altă notă muzicală. În notația englezească se folosesc unele litere mari ale alfabetului pentru notele muzicale, astfel: litera A pentru nota la, litera B pentru nota si, apoi, în ordine, litera C pentru nota do, litera D pentru nota re, litera E pentru nota mi, litera F pentru nota fa și litera G pentru nota sol.

    Variabila m, declarată alăturat, memorează literele corespunzătoare notației englezești pentru două note care formează un interval muzical, date în ordinea din gamă.

    Știind că în câmpul nota1 se memorează una dintre literele C, D, E, F sau G, scrieți o secvență de instrucțiuni C/C++ în urma executării căreia să se afișeze pe ecran mesajul TERTA, dacă intervalul respectiv formează o terță, sau mesajul NU, în caz contrar.

    Exemplu: dacă în câmpul nota1 se memorează litera G (pentru nota sol), iar în câmpul nota2 se memorează litera B (pentru nota si), se afișează mesajul TERTA.

    struct interval
    { char nota1;
      char nota2;
    }m;
    Arată răspunsul și explicația
    if ((m.nota1 <= 'E' && m.nota2 == m.nota1 + 2) || (m.nota1 >= 'F' && m.nota2 == m.nota1 - 5))
        cout << "TERTA";
    else cout << "NU";
    
    În gamă notele sunt, în ordine, C, D, E, F, G, A, B. O terță sare peste o singură notă. Pentru C, D și E, nota aflată la două poziții după ea este tot în ordinea alfabetului: nota1 + 2 (C→E, D→F, E→G). Pentru F și G, ordinea gamei continuă cu A și B, aflate în alfabet cu 5 poziții înainte: F→A și G→B, adică nota1 − 5.

Subiectul al III-lea30 de puncte

  1. Exercițiul 110p

    Un număr natural nenul, n, se numește moderat dacă este egal cu produsul a două numere prime, iar acestea sunt consecutive în șirul numerelor prime (2, 3, 5, 7, 11, 13, 17...).

    Subprogramul moderat are un singur parametru, n, prin care primește un număr natural (n∈[1,105]). Subprogramul returnează valoarea 1, dacă n este un număr moderat, sau valoarea 0, în caz contrar.

    Scrieți definiția completă a subprogramului.

    Exemplu: dacă n=35, subprogramul returnează 1 (35=5·7), iar dacă n=18 sau n=55 sau n=4, subprogramul returnează 0.

    Arată răspunsul și explicația
    int moderat(int n)
    {
        int p, q, k, d, prim;
        if (n < 6) return 0;
        p = 2;
        while (n % p != 0) p++;
        q = n / p;
        if (q <= p) return 0;
        for (k = p + 1; k <= q; k++)
        {
            prim = 1;
            for (d = 2; d * d <= k; d++)
                if (k % d == 0) prim = 0;
            if (k == q) return prim;
            if (prim == 1) return 0;
        }
        return 0;
    }
    
    Cel mai mic divizor p ≥ 2 al lui n este sigur prim. Dacă n este produsul a două numere prime consecutive, p este cel mai mic dintre ele, iar celălalt este q = n/p, mai mare decât p.
    Se parcurg numerele de la p+1 la q: dacă vreunul dintre ele, înainte de q, este prim, atunci p și q nu sunt consecutive și se returnează 0; când se ajunge la q, rezultatul este 1 exact dacă q este prim. Numerele sub 6 nu pot fi moderate (cel mai mic este 2·3).
  2. Exercițiul 210p

    O grădină este împărțită în parcele pătrate identice, dispuse pe rânduri succesive. Toate parcelele de pe un rând conțin același tip de plante (doar flori sau doar gazon) și oricare două rânduri alăturate conțin tipuri diferite de plante, pe primul rând fiind gazon. Pentru fiecare parcelă se memorează înălțimea acesteia, egală cu înălțimea medie a plantelor conținute, exprimată în decimetri. Pentru a pune în valoare florile, fiecare parcelă cu flori trebuie să fie mai înaltă cu cel puțin un decimetru decât oricare dintre parcelele cu gazon de pe rândul vecin anterior. S-a hotărât tunderea parcelelor cu gazon prea înalte, astfel încât ele să fie aduse la înălțimea maximă permisă.

    Scrieți un program C/C++ care citește de la tastatură două numere naturale din intervalul [2,102], m și n, apoi elementele unui tablou bidimensional cu m linii și n coloane, numere naturale din intervalul [2,10], reprezentând înălțimile parcelelor, în ordinea dispunerii acestora în grădină, rând după rând, și pe fiecare rând de la stânga la dreapta. Programul modifică apoi tabloul în memorie corespunzător situației terenului după tunderea gazonului și afișează pe ecran tabloul obținut, fiecare linie a tabloului pe câte o linie a ecranului, elementele de pe aceeași linie fiind separate prin câte un spațiu.

    Exemplu: pentru m=4, n=6 și tabloul

    Figura din enunț
    Arată răspunsul și explicația
    #include <iostream>
    using namespace std;
    
    int main()
    {
        int m, n, a[100][100], i, j, minim;
        cin >> m >> n;
        for (i = 0; i < m; i++)
            for (j = 0; j < n; j++)
                cin >> a[i][j];
        for (i = 1; i < m; i = i + 2)
        {
            minim = a[i][0];
            for (j = 1; j < n; j++)
                if (a[i][j] < minim) minim = a[i][j];
            for (j = 0; j < n; j++)
                if (a[i - 1][j] > minim - 1) a[i - 1][j] = minim - 1;
        }
        for (i = 0; i < m; i++)
        {
            for (j = 0; j < n; j++)
                cout << a[i][j] << ' ';
            cout << '\n';
        }
        return 0;
    }
    
    Primul rând (linia 0) are gazon, deci rândurile cu flori sunt liniile 1, 3, 5, … Pentru fiecare astfel de linie i se află înălțimea minimă a florilor. Orice parcelă cu gazon de pe rândul anterior, linia i−1, trebuie să fie cu cel puțin un decimetru mai joasă decât toate florile, deci cel mult minim−1; cele mai înalte se tund exact la această valoare. Dacă ultimul rând are gazon, după el nu mai urmează flori și rămâne neschimbat.
  3. Exercițiul 3.a2p

    Șirul 0, 0, 1, 4, 13, 38, 105, 280, 729 .... este definit astfel: f₁=f₂=0, f₃=1, fₙ=4∙fₙ₋₁-3∙fₙ₋₂-2∙fₙ₋₃ (unde n este un număr natural n≥4).

    Se citesc de la tastatură trei numere naturale x, y și z (x≤y<z≤109), valorile a trei termeni aflați pe poziții consecutive în șirul dat, și se cere să se scrie în fișierul bac.txt, în ordine descrescătoare, separați prin câte un spațiu, toți termenii șirului care sunt mai mici sau egali cu z. Proiectați un algoritm eficient din punctul de vedere al timpului de executare și al spațiului de memorie utilizat.

    Exemplu: dacă se citesc numerele 38 105 280 fișierul conține numerele 280 105 38 13 4 1 0 0

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

    Arată răspunsul și explicația
    Formula termenului general se poate întoarce: dacă a, b, c, d sunt patru termeni consecutivi, d = 4c − 3b − 2a, deci termenul dinaintea lor este a = (4c − 3b − d)/2. Din ultimii trei termeni scriși se obține, așadar, termenul de dinaintea lor.
    
    Se scriu în fișier z, y și x, în această ordine (descrescătoare). Apoi, repetat, se calculează termenul anterior, (4·y − 3·x − z)/2, se scrie și se mută fereastra: z primește y, y primește x, iar x noul termen. Primii doi termeni ai șirului sunt singurele valori 0, deci algoritmul se oprește după ce au fost scrise două valori 0 (numărând și eventualele zerouri dintre valorile citite).
    
    Eficiență: fiecare termen se obține în timp constant din cei trei scriși înaintea lui, deci timpul este liniar în numărul de termeni scriși; se păstrează doar trei valori, fără tablou, deci memoria folosită este constantă.
  4. Exercițiul 3.b8p

    Șirul 0, 0, 1, 4, 13, 38, 105, 280, 729 .... este definit astfel: f₁=f₂=0, f₃=1, fₙ=4∙fₙ₋₁-3∙fₙ₋₂-2∙fₙ₋₃ (unde n este un număr natural n≥4).

    Se citesc de la tastatură trei numere naturale x, y și z (x≤y<z≤109), valorile a trei termeni aflați pe poziții consecutive în șirul dat, și se cere să se scrie în fișierul bac.txt, în ordine descrescătoare, separați prin câte un spațiu, toți termenii șirului care sunt mai mici sau egali cu z. Proiectați un algoritm eficient din punctul de vedere al timpului de executare și al spațiului de memorie utilizat.

    Exemplu: dacă se citesc numerele 38 105 280 fișierul conține numerele 280 105 38 13 4 1 0 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()
    {
        long long x, y, z, crt;
        int zerouri;
        cin >> x >> y >> z;
        ofstream fout("bac.txt");
        fout << z << ' ' << y << ' ' << x;
        zerouri = (y == 0) + (x == 0);
        while (zerouri < 2)
        {
            crt = (4 * y - 3 * x - z) / 2;
            fout << ' ' << crt;
            if (crt == 0) zerouri++;
            z = y;
            y = x;
            x = crt;
        }
        fout.close();
        return 0;
    }
    
    Programul face pașii de la 3.a. Numărul de zerouri pornește de la cele aflate deja printre valorile citite (de exemplu pentru 0 0 1 nu mai trebuie calculat nimic). Termenii ajung la 10^9, iar 4·y trece de limita tipului int, de aceea se folosește long long.

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