Bac informatică 2025 Model, rezolvată

Lucrarea „2025 Model” 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 intervalul căruia îi aparține valoarea variabilei reale x, dacă și numai dacă expresia C/C++ de mai jos are valoarea 1.

    !(x<2004) && !(x<2005 || x>2024) && !(x>2025)
    • a)[2004,2005]
    • b)[2004,2024]
    • c)[2005,2024]
    • d)[2005,2025]
    Arată răspunsul și explicația

    Răspuns corect: c) [2005,2024]

    !(x<2004) înseamnă x>=2004, !(x<2005 || x>2024) înseamnă x>=2005 && x<=2024, iar !(x>2025) înseamnă x<=2025. Toate trei trebuie să fie adevărate, iar condiția din mijloc este cea mai strictă: x aparține intervalului [2005,2024].

  2. Exercițiul 24p

    Subprogramul f este definit alăturat.

    Indicați valoarea f(2,5).

    int f(int n,int x)
    {  if(n>0)
         return f(f(n-2,x)-2,x-5);
       return x;
    }
    • a)3
    • b)0
    • c)-2
    • d)-5
    Arată răspunsul și explicația

    Răspuns corect: d) -5

    f(2,5) = f(f(0,5)-2, 0). f(0,5) = 5, deci se calculează f(3,0) = f(f(1,0)-2, -5).

    f(1,0) = f(f(-1,0)-2, -5); f(-1,0) = 0, deci f(1,0) = f(-2,-5) = -5. Atunci f(3,0) = f(-7,-5) = -5, iar f(2,5) = -5.

  3. Exercițiul 34p

    Variabila s poate accesa un șir de cel mult 20 de caractere, variabila aux este de tip char, iar celelalte variabile sunt de tip întreg.

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

    strcpy(s,"ROMANIA"); i=strlen(s)-1; j=3;
    while(j>=0)
    { aux=s[i]; s[i]=s[i-j]; s[i-j]=aux;
      i=i-j; j=j-1;
    }
    • a)ARMONIA
    • b)IAMARON
    • c)MANIARO
    • d)MARONIA
    Arată răspunsul și explicația

    Răspuns corect: a) ARMONIA

    La început s este ROMANIA (pozițiile de la 0 la 6), i=6 și j=3. Fiecare pas interschimbă caracterele de pe pozițiile i și i-j, apoi i scade cu j, iar j scade cu 1.

    Cu j=3 se schimbă pozițiile 6 și 3, dar pe amândouă este A, deci șirul nu se schimbă; i devine 3. Cu j=2 se schimbă pozițiile 3 și 1: RAMONIA; i devine 1. Cu j=1 se schimbă pozițiile 1 și 0: ARMONIA; i devine 0. Cu j=0 poziția 0 se schimbă cu ea însăși, iar bucla se oprește. Rezultatul este ARMONIA.

  4. Exercițiul 44p

    Un graf orientat are 6 vârfuri, numerotate de la 1 la 6, și arcele:

    1. (1,2)
    2. (1,6)
    3. (2,3)
    4. (3,1)
    5. (3,4)
    6. (4,5)
    7. (5,3)
    8. (5,6)

    Indicați un circuit elementar al acestui graf.

    • a)1,2,3
    • b)1,2,3,1
    • c)1,2,3,4,5,3,1
    • d)1,2,3,4,5,6,1
    Arată răspunsul și explicația

    Răspuns corect: b) 1,2,3,1

    Un circuit elementar pornește dintr-un vârf, trece prin vârfuri distincte și revine în vârful de plecare, pe arce din graf. Arcele (1,2), (2,3) și (3,1) formează circuitul 1,2,3,1.

    a) nu revine în vârful 1; c) trece de două ori prin vârful 3, deci nu e elementar; d) folosește arcul (6,1), care nu există.

  5. Exercițiul 54p

    Indicați numărul de noduri ale unui graf neorientat, complet, cu 300 de muchii.

    • a)25
    • b)30
    • c)299
    • d)301
    Arată răspunsul și explicația

    Răspuns corect: a) 25

    Un graf neorientat complet cu n noduri are câte o muchie între oricare două noduri, adică n·(n−1)/2 muchii. n·(n−1)/2 = 300 înseamnă n·(n−1) = 600 = 25·24, deci n = 25.

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.

    Scrieți valoarea afișată în urma executării algoritmului, dacă se citesc, în această ordine, numerele 15, 3, 4.

    citește n,x,y
      (numere naturale nenule, x≤n, y≤n)
     nr←0
    ┌pentru i←n,1,-1 execută
    │┌dacă i%x=0 și i%y≠0 atunci
    ││ nr←nr+1
    ││altfel
    ││┌dacă i%x≠0 și i%y=0 atunci
    │││ nr←nr+1
    ││└■
    │└■
    └■
     scrie nr
    Arată răspunsul și explicația

    Răspunsul din barem: 6

    6
    
    Algoritmul numără valorile i de la 1 la n care se împart la exact unul dintre numerele x și y.
    Pentru n=15, x=3, y=4: multiplii lui 3 sunt 3, 6, 9, 12, 15, iar ai lui 4 sunt 4, 8, 12. 12 se împarte la amândouă, deci nu se numără; rămân 3, 6, 9, 15, 4 și 8: 6 valori.
  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.

    Scrieți două seturi distincte de date de intrare, astfel încât, în urma executării algoritmului, pentru fiecare dintre acestea să se afișeze valoarea 0.

    citește n,x,y
      (numere naturale nenule, x≤n, y≤n)
     nr←0
    ┌pentru i←n,1,-1 execută
    │┌dacă i%x=0 și i%y≠0 atunci
    ││ nr←nr+1
    ││altfel
    ││┌dacă i%x≠0 și i%y=0 atunci
    │││ nr←nr+1
    ││└■
    │└■
    └■
     scrie nr
    Arată răspunsul și explicația
    Exemplu: 5 2 2 și 7 3 3
    
    Dacă x = y, orice număr care se împarte la unul se împarte și la celălalt, deci niciun i nu se numără și se afișează 0. Merge orice set cu numere nenule în care x = y ≤ n, de exemplu n=5, x=2, y=2 sau n=7, x=3, y=3.
  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.

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

    citește n,x,y
      (numere naturale nenule, x≤n, y≤n)
     nr←0
    ┌pentru i←n,1,-1 execută
    │┌dacă i%x=0 și i%y≠0 atunci
    ││ nr←nr+1
    ││altfel
    ││┌dacă i%x≠0 și i%y=0 atunci
    │││ nr←nr+1
    ││└■
    │└■
    └■
     scrie nr
    Arată răspunsul și explicația
    #include <iostream>
    using namespace std;
    
    int main()
    {
        int n, x, y, nr = 0, i;
        cin >> n >> x >> y;
        for (i = n; i >= 1; i--)
            if (i % x == 0 && i % y != 0) nr = nr + 1;
            else if (i % x != 0 && i % y == 0) nr = nr + 1;
        cout << nr;
        return 0;
    }
    
    pentru i←n,1,-1 execută devine for (i = n; i >= 1; i--). Structura dacă…altfel dacă devine if…else if.
  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.

    Scrieți în pseudocod un algoritm echivalent cu cel dat, înlocuind adecvat structura pentru...execută cu o structură repetitivă cu test inițial.

    citește n,x,y
      (numere naturale nenule, x≤n, y≤n)
     nr←0
    ┌pentru i←n,1,-1 execută
    │┌dacă i%x=0 și i%y≠0 atunci
    ││ nr←nr+1
    ││altfel
    ││┌dacă i%x≠0 și i%y=0 atunci
    │││ nr←nr+1
    ││└■
    │└■
    └■
     scrie nr
    Arată răspunsul și explicația
    citește n,x,y (numere naturale nenule, x≤n, y≤n)
    nr←0
    i←n
    ┌cât timp i≥1 execută
    │┌dacă i%x=0 și i%y≠0 atunci
    ││ nr←nr+1
    ││altfel
    ││┌dacă i%x≠0 și i%y=0 atunci
    │││ nr←nr+1
    ││└■
    │└■
    │ i←i-1
    └■
    scrie nr
    
    Cu cât timp, contorul se gestionează explicit: i primește valoarea inițială n înainte de buclă, se continuă cât timp i≥1, iar i←i-1 se face la sfârșitul corpului.
  5. Exercițiul 26p

    Utilizând metoda backtracking, se generează toate numerele formate din cifre distincte, cifre a căror sumă să fie 6. Primele patru soluții generate sunt, în această ordine: 1023, 1032, 105 și 1203.

    Scrieți cea de a cincea și cea de a șasea soluție generată.

    Arată răspunsul și explicația
    123 1230
    
    Numerele se construiesc cifră cu cifră, încercând cifrele în ordine crescătoare, iar un număr se scrie de îndată ce suma cifrelor lui ajunge 6 — după care se încearcă și prelungirea lui, pentru că o cifră 0 nefolosită păstrează suma.
    După 1203, cu prefixul 12 următoarea cifră încercată este 3: 123 are suma 6. Prelungit cu 0, încă nefolosit, dă 1230, tot cu suma 6 și cifre distincte. Abia apoi urmează numerele care încep cu 13, de la 1302.
  6. Exercițiul 36p

    Variabila m memorează date despre o mașină de epocă: anul fabricației și data (ziua și luna) ultimei prezentări în cadrul unei expoziții de profil care a avut loc în anul curent.

    Știind că expresiile C/C++ de mai jos memorează anul fabricației mașinii (număr natural din intervalul [1880,1950]), ziua (număr natural din intervalul [1,31]) și luna (șir de cel mult 15 caractere) din anul curent la care a fost prezentată aceasta la o expoziție, scrieți definiția unei structuri, cu eticheta epoca, înregistrare care să permită memorarea datelor unei mașini de epocă, și declarați variabila m, de acest tip.

    m.anFabricatie  m.expo.zi m.expo.luna
    Arată răspunsul și explicația
    struct data
    {   int zi;
        char luna[16];
    };
    
    struct epoca
    {   int anFabricatie;
        data expo;
    } m;
    
    m.anFabricatie este un număr natural, iar m.expo.zi și m.expo.luna arată că expo este la rândul lui o structură, cu ziua (număr) și luna (șir de cel mult 15 caractere, deci un tablou de 16, cu loc pentru terminatorul '\0'). Structura data poate fi definită și în interiorul lui epoca.

Subiectul al III-lea30 de puncte

  1. Exercițiul 110p

    Două numere se numesc oglindite dacă fiecare se obține din celălalt, prin parcurgerea cifrelor acestuia de la dreapta la stânga. Două numere se numesc par-oglindite dacă numerele obținute din acestea, prin îndepărtarea tuturor cifrelor lor impare sau nule, sunt oglindite.

    Subprogramul pao are trei parametri:

    x și y, prin care primește câte un număr natural din intervalul [0,109];

    rez, prin care furnizează valoarea 1, dacă x și y sunt par-oglindite, sau valoarea 0, în caz contrar.

    Scrieți definiția completă a subprogramului.

    Exemplu: dacă x=814 și y=7003485, sau x=14 și y=700345, după apel rez=1, iar dacă x=814 și y=7003465, sau x=814 și y=7003845, sau x=15 și y=510, după apel rez=0.

    Arată răspunsul și explicația
    void pao(int x, int y, int &rez)
    {
        int a = 0, p = 1, r = 0, c;
        while (x > 0)
        {
            c = x % 10;
            if (c != 0 && c % 2 == 0)
            {
                a = a + c * p;
                p = p * 10;
            }
            x = x / 10;
        }
        while (y > 0)
        {
            c = y % 10;
            if (c != 0 && c % 2 == 0) r = r * 10 + c;
            y = y / 10;
        }
        if (a == r && a != 0) rez = 1;
        else rez = 0;
    }
    
    Din x se păstrează cifrele pare nenule în ordinea lor, formând numărul a (fiecare cifră păstrată se pune în fața celor de dinainte, cu puterea p a lui 10). Din y se păstrează tot cifrele pare nenule, dar în ordine inversă: luate de la dreapta și alipite la sfârșit, formează numărul r. x și y sunt par-oglindite exact când a = r.
    Cazul în care niciunul nu are cifre pare nenule dă a = r = 0; exemplul x=15, y=510 cere atunci rez=0, de aceea se verifică și a ≠ 0.
  2. Exercițiul 210p

    Scrieți un program C/C++ care citește de la tastatură două numere naturale din intervalul [2,102], k și n (k≥n), și construiește în memorie un tablou bidimensional cu n linii și n coloane, astfel încât parcurgând diagonala principală, de sus în jos, să se obțină un șir strict crescător format din primii n multipli naturali nenuli ai lui k, și parcurgând fiecare linie a sa, de la stânga la dreapta, să se obțină câte un șir strict descrescător de numere naturale consecutive.

    Programul 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 k=5 și n=4 se obține tabloul alăturat.

    5432
    111098
    17161514
    23222120
    Arată răspunsul și explicația
    #include <iostream>
    using namespace std;
    
    int main()
    {
        int k, n, a[100][100], i, j;
        cin >> k >> n;
        for (i = 0; i < n; i++)
            for (j = 0; j < n; j++)
                a[i][j] = k * (i + 1) + i - j;
        for (i = 0; i < n; i++)
        {
            for (j = 0; j < n; j++)
                cout << a[i][j] << ' ';
            cout << '\n';
        }
        return 0;
    }
    
    Pe diagonala principală, linia i (numerotând de la 0) are multiplul k·(i+1). Pe fiecare linie valorile scad cu 1 de la stânga la dreapta, deci elementul de pe coloana j este cu i−j mai mare decât cel de pe diagonală: k·(i+1) + i − j. Condiția k ≥ n face ca toate valorile să fie numere naturale nenule.
  3. Exercițiul 3.a2p

    La o expoziție auto se află, în șir, mașini de epocă, fiecare având câte un cod, format prin alipirea, în această ordine, a două numere naturale nenule: identificatorul colecționarului care deține mașina, respectiv anul fabricației acesteia.

    Fișierul bac.txt conține numere naturale: pe prima linie un număr x (x∈[1880,1950]), reprezentând un an calendaristic, iar pe a doua linie cel mult 105 numere din intervalul [104,109], reprezentând codurile mașinilor, în ordinea din șirul în care sunt expuse. Numerele aflate pe aceeași linie în fișier sunt separate prin câte un spațiu.

    Se cere să se afișeze pe ecran identificatorii colecționarilor care dețin ultimele două mașini, din șirul celor expuse, ambele fiind fabricate în anul x și aflate în șir pe poziții consecutive, ca în exemplu. Numerele, nu neapărat distincte, sunt afișate în ordinea în care mașinile corespunzătoare apar în șir, separate printr-un spațiu, iar dacă nu există două astfel de mașini, se afișează pe ecran mesajul nu exista. Proiectați un algoritm eficient din punctul de vedere al memoriei utilizate și al timpului de executare.

    Exemplu: dacă fișierul conține numerele de mai jos, atunci pe ecran se afișează 3 15

    1925
    31885 21925 8931925 31925 121900 11925 31925 151925 61950 201925 121880

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

    Arată răspunsul și explicația
    Codul unei mașini se termină cu anul fabricației, care are patru cifre: anul este codul % 10000, iar identificatorul colecționarului este codul / 10000.
    
    Se citește anul x, apoi codurile pe rând, fără să fie memorate; se păstrează doar codul anterior (ant) și ultimii doi identificatori găsiți (pu și u, pornite de la -1). Pentru fiecare cod curent, dacă atât el, cât și codul anterior au anul x, perechea lor devine ultima găsită: pu = ant / 10000, u = crt / 10000. Apoi codul curent devine cel anterior. La final, dacă u a rămas -1 se afișează nu exista, altfel pu și u.
    
    Eficiență: fiecare cod se prelucrează o singură dată, în timp constant, deci algoritmul este liniar în numărul de coduri; se folosesc doar câteva variabile simple, deci memoria este constantă.
  4. Exercițiul 3.b8p

    La o expoziție auto se află, în șir, mașini de epocă, fiecare având câte un cod, format prin alipirea, în această ordine, a două numere naturale nenule: identificatorul colecționarului care deține mașina, respectiv anul fabricației acesteia.

    Fișierul bac.txt conține numere naturale: pe prima linie un număr x (x∈[1880,1950]), reprezentând un an calendaristic, iar pe a doua linie cel mult 105 numere din intervalul [104,109], reprezentând codurile mașinilor, în ordinea din șirul în care sunt expuse. Numerele aflate pe aceeași linie în fișier sunt separate prin câte un spațiu.

    Se cere să se afișeze pe ecran identificatorii colecționarilor care dețin ultimele două mașini, din șirul celor expuse, ambele fiind fabricate în anul x și aflate în șir pe poziții consecutive, ca în exemplu. Numerele, nu neapărat distincte, sunt afișate în ordinea în care mașinile corespunzătoare apar în șir, separate printr-un spațiu, iar dacă nu există două astfel de mașini, se afișează pe ecran mesajul nu exista. Proiectați un algoritm eficient din punctul de vedere al memoriei utilizate și al timpului de executare.

    Exemplu: dacă fișierul conține numerele de mai jos, atunci pe ecran se afișează 3 15

    1925
    31885 21925 8931925 31925 121900 11925 31925 151925 61950 201925 121880

    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("bac.txt");
        int x, ant = 0, crt, pu = -1, u = -1;
        fin >> x;
        while (fin >> crt)
        {
            if (ant % 10000 == x && crt % 10000 == x)
            {
                pu = ant / 10000;
                u = crt / 10000;
            }
            ant = crt;
        }
        fin.close();
        if (u == -1) cout << "nu exista";
        else cout << pu << ' ' << u;
        return 0;
    }
    
    Programul face pașii de la 3.a. ant pornește de la 0, care nu are anul x, deci primul cod nu formează o pereche cu nimic. Codurile ajung până la 10^9 și încap î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