Sari la conținut

Bac informatică 2021 Varianta 1, rezolvată

Varianta 1 de la Bacalaureatul la Informatică (Mate-Info, C/C++): conține 3 subiecte (90 de puncte) și are un timp de lucru de 3 ore. Sub fiecare exercițiu găsești răspunsul corect și rezolvarea.

Subiecte oficiale publicate de Ministerul Educației. Rezolvări realizate de subac. Actualizat la .

📌 Despre Varianta 1 din 2021

Varianta 1 din 2021 trece prin expresii logice, recursivitate, matrice, grafuri și arbori, backtracking, structuri, descompunerea în factori primi, șiruri de caractere și fișiere. Este o variantă echilibrată, bună ca test complet.

Subiectul I (20p): 5 grile: o expresie care verifică dacă două numere sunt pare, un subprogram recursiv care șterge dintr-un număr cifrele egale cu c, accesul la un element de pe diagonala secundară a unei matrice, un ciclu elementar într-un graf neorientat și numărul minim de noduri de pe nivelul 3 al unui arbore cu rădăcină.

Subiectul al II-lea (40p): Un algoritm în pseudocod cu o interschimbare și un pentru descrescător care afișează cifrele 1 și 2, o problemă de backtracking cu grupuri de păsări cântătoare și o secvență care scade o fracție memorată într-o structură fractie din fracția 2020/2021.

Subiectul al III-lea (30p): Un subprogram cu factori primi (divPrim, suma divizorilor primi care apar la o putere impară), o problemă cu șiruri de caractere care afișează primele k cuvinte terminate cu vocală și o problemă de eficiență care caută ultimii doi termeni vecini care au ca sufix numărul x, citiți din fișierul bac.txt.

⚠️ La ce să fii atent

  • La I.1: Variantele c) și d) verifică doar că x și y au aceeași paritate, deci sunt adevărate și pentru două numere impare, de exemplu x=3, y=5.
  • La I.5: Niciun nivel nu poate avea același număr de noduri ca altul, deci fiecare nod de pe nivelurile 0, 1 și 2 trebuie să aibă cel puțin 2 fii. Nivelurile au 1, 2, 4 și 8 noduri, deci minimul este 8.
  • La II.1.a: Nu uita interschimbarea de la început! Pentru 8 și 5, x devine 5 și y devine 8, deci bucla merge de la 8 la 5, iar rezultatul este 1111121121.
  • La II.1.b: Interschimbarea schimbă și numărul de pași, și pragul cu care se compară nr. De aceea merge și o valoare mai mică decât 10: pentru y=6 și pentru y=15, cifra 2 se afișează de exact trei ori.
  • La III.3: Cum x are trei cifre, un termen îl are pe x drept sufix dacă ultimele lui trei cifre sunt chiar x, adică restul împărțirii la 1000 este x. Se cer ultimii doi termeni vecini, deci păstrează mereu ultima pereche găsită.

Subiectul I

20 de puncte
  1. Exercițiul 1 4p Expresii și operatori

    Indicați o expresie C/C++ care are valoarea 1 dacă și numai dacă valorile variabilelor întregi x și y sunt numere pare.

    • a)x%2==0 && (y+1)%2!=0
    • b)(x-y)/2==0
    • c)(x+y)%2==0 && (x-y)%2==0
    • d)x%2==y%2
    Vezi rezolvarea

    Răspuns corect: a) x%2==0 && (y+1)%2!=0

    Se cere ca amândouă să fie pare.

    Varianta a): x%2==0 spune că x e par, iar (y+1)%2!=0 spune că y+1 e impar — ceea ce se întâmplă exact când y e par. Deci a) e adevărată exact când amândouă sunt pare.

    Celelalte nu:

    • b) (x-y)/2==0 e împărțire întreagă: e adevărată când x și y diferă cu cel mult 1, fără legătură cu paritatea.
    • c) și d) spun amândouă că x și y au aceeași paritate — sunt adevărate și când amândouă sunt impare, de exemplu x=3, y=5.
  2. Exercițiul 2 4p Recursivitate

    Subprogramul f este definit alăturat.

    Indicați valorile pe care le pot avea parametrii n și c, astfel încât, în urma apelului, f(n,c) să aibă valoarea 2021.

    int f(int n,int c)
    { if(n==0) return 0;
      else
        if(n%10==c) return f(n/10,c);
        else return n%10+10*f(n/10,c);
    }
    • a)n=2021 și c=0
    • b)n=200211 și c=2
    • c)n=312032 și c=3
    • d)n=720721 și c=7
    Vezi rezolvarea

    Răspuns corect: d) n=720721 și c=7

    Subprogramul reconstruiește numărul ștergând toate cifrele egale cu c: dacă ultima cifră e c, o sare, altfel o păstrează la coadă și continuă cu restul numărului.

    variantăce se ștergerezultat
    a) f(2021,0)zerourile221
    b) f(200211,2)cifrele 211
    c) f(312032,3)cifrele 31202
    d) f(720721,7)cifrele 72021

    Din 720721, scoțând cei doi de 7, rămâne 2021 — varianta d).

  3. Exercițiul 3 4p Tablouri bidimensionale

    Variabila m memorează elementele unui tablou bidimensional cu 100 de linii și 100 de coloane, numerotate de la 0 la 99.

    Indicați expresia C/C++ prin care poate fi accesat un element aflat pe diagonala secundară a tabloului.

    • a)m[42/42]
    • b)m[42|42]
    • c)m[42]:[57]
    • d)m[42][57]
    Vezi rezolvarea

    Răspuns corect: d) m[42][57]

    Un element de pe diagonala secundară are suma indicilor egală cu numărul de linii minus 1, aici 99.

    m[42][57] are 42+57 = 99, deci e chiar pe diagonala secundară — varianta d).

    Celelalte nici măcar nu sunt scrise corect: a) și b) au un singur indice, iar expresiile 42/42 și 42|42 dau un număr, nu o pereche; c) folosește două puncte în loc de paranteze drepte.

  4. Exercițiul 4 4p Grafuri neorientate

    Un graf neorientat are 6 noduri, numerotate de la 1 la 6, și muchiile:

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

    Indicați un ciclu 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
    Vezi rezolvarea

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

    Un ciclu pornește și se întoarce în același nod, iar unul elementar nu repetă niciun alt nod pe drum.

    Varianta b), 1,2,3,1, folosește muchiile [1,2], [2,3] și [3,1] — toate trei există — și nu repetă niciun nod între capete. E un ciclu elementar.

    • a) 1,2,3 nu se întoarce în 1, deci e lanț, nu ciclu.
    • c) 1,2,3,4,5,3,1 trece de două ori prin nodul 3: e ciclu, dar nu elementar.
    • d) 1,2,3,4,5,6,1 ar avea nevoie de muchia [6,1], care nu există.
  5. Exercițiul 5 4p Arbori

    Î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).

    Într-un arbore cu rădăcină toate nodurile de pe același nivel au un număr egal de „fii” și nu există două niveluri diferite cu același număr de noduri.

    Indicați numărul minim de noduri de pe nivelul 3.

    • a)12
    • b)9
    • c)8
    • d)5
    Vezi rezolvarea

    Răspuns corect: c) 8

    Numărul de noduri de pe un nivel se obține înmulțind numărul de noduri de pe nivelul dinainte cu numărul de fii ai fiecăruia. Condiția e ca niciun nivel să nu aibă același număr de noduri ca altul, iar nivelul 0 are 1 nod.

    Încearcă valorile mici:

    nivelnoduride ce nu mai puțin
    01rădăcina
    121 ar repeta nivelul 0
    24cu un singur fiu ar ieși tot 2, ca nivelul 1
    38cu un singur fiu ar ieși tot 4, ca nivelul 2

    Deci minimul e 8, varianta c). Dacă rădăcina ar avea 3 fii, nivelurile ar deveni 3, 6 și cel puțin 12 — mai mult.

Subiectul al II-lea

40 de puncte
  1. Exercițiul 1.a 6p Algoritmi în pseudocod

    Algoritmul alăturat este reprezentat în pseudocod.

    S-a notat cu a↔b operația de interschimbare a valorilor variabilelor a și b.

    Scrieți ce se afișează în urma executării algoritmului dacă se citesc, în această ordine, numerele 8 și 5.

    citește x,y
      (numere naturale nenule)
    ┌dacă x>y atunci x↔y
    └■
     nr←1
    ┌pentru i←y,x,-1 execută
    │ scrie 1
    │┌dacă nr≥x atunci
    ││ scrie 2
    │└■
    │ nr←nr*3
    │ scrie 1
    └■
    Vezi rezolvarea

    Răspunsul din barem: 1111121121

    Se citesc 8 și 5, iar cum x>y, ele se interschimbă: x=5, y=8. Bucla merge descrescător, de la 8 la 5 — patru pași. La fiecare pas se scrie 1, eventual 2, apoi iar 1, iar nr se triplează.

    inr la intrarenr≥5?se scrie
    81nu11
    73nu11
    69da121
    527da121

    Puse cap la cap: 1111121121.

    Cifra 2 apare abia din al treilea pas, fiindcă nr ia valorile 1, 3, 9, 27 — puterile lui 3 — și abia 9 ajunge la 5.

  2. Exercițiul 1.b 6p Algoritmi în pseudocod

    Același algoritm ca la 1.a.

    S-a notat cu a↔b operația de interschimbare a valorilor variabilelor a și b.

    Dacă pentru variabila x se citește valoarea 10, scrieți două numere care pot fi citite pentru variabila y, astfel încât, în urma executării algoritmului, pentru fiecare dintre acestea, cifra 2 să fie afișată doar de trei ori.

    Vezi rezolvarea

    6 15

    Cifra 2 se scrie o dată la fiecare pas în care nr≥x, iar nr ia valorile 1, 3, 9, 27, 81… Deci contează câți pași are bucla și de la al câtelea nr întrece x.

    y=15: nu se interschimbă nimic, x=10, bucla merge de la 15 la 10 — șase pași. nr întrece 10 abia la valoarea 27, adică la al patrulea pas, deci 2 se scrie la pașii 4, 5 și 6: de trei ori.

    y=6: aici x>y, deci se interschimbă și devin x=6, y=10. Bucla merge de la 10 la 6 — cinci pași — iar nr întrece 6 de la valoarea 9, adică de la al treilea pas: pașii 3, 4 și 5, tot de trei ori.

    Sunt singurele două valori care merg: interschimbarea de la început schimbă și numărul de pași, și pragul cu care se compară nr.

  3. Exercițiul 1.c 10p Algoritmi în pseudocod

    Același algoritm ca la 1.a.

    S-a notat cu a↔b operația de interschimbare a valorilor variabilelor a și b.

    Scrieți programul C/C++ corespunzător algoritmului dat, fără a utiliza eventuale subprograme predefinite pentru interschimbare.

    Vezi rezolvarea
    #include <iostream>
    using namespace std;
    
    int main()
    {
        int x, y, nr, aux;
        cin >> x >> y;
        if (x > y)
        {
            aux = x;
            x = y;
            y = aux;
        }
        nr = 1;
        for (int i = y; i >= x; i--)
        {
            cout << 1;
            if (nr >= x)
                cout << 2;
            nr = nr * 3;
            cout << 1;
        }
        return 0;
    }
  4. Exercițiul 1.d 6p Algoritmi în pseudocod

    Același algoritm ca la 1.a.

    S-a notat cu a↔b operația de interschimbare a valorilor variabilelor a și b.

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

    Vezi rezolvarea

    `` citește x,y (numere naturale nenule) ┌dacă x>y atunci x↔y └■ nr←1 i←y ┌cât timp i≥x execută │ scrie 1 │┌dacă nr≥x atunci ││ scrie 2 │└■ │ nr←nr*3 │ scrie 1 │ i←i-1 └■ ``

    pentru i←y,x,-1 face trei lucruri deodată: pornește i de la y, verifică la fiecare pas dacă a coborât sub x și îl scade cu 1. Cu cât timp ele se scriu separat: inițializarea înaintea buclei, condiția i≥x în capul ei, iar i←i-1 la sfârșitul corpului.

    Pasul e -1, deci condiția de continuare e i≥x, nu i≤x — bucla coboară, nu urcă.

  5. Exercițiul 2 6p Backtracking

    Utilizând metoda bactracking se generează toate grupurile de cel puțin două păsări cântătoare din mulțimea {cinteză, ciocârlie, mierlă, privighetoare, scatiu}, astfel încât mierla și privighetoarea să nu fie în același grup. Două grupuri diferă prin cel puțin o pasăre. Primele patru soluții generate sunt, în această ordine:

    1. (cinteză, ciocârlie)
    2. (cinteză, ciocârlie, mierlă)
    3. (cinteză, ciocârlie, mierlă, scatiu)
    4. (cinteză, ciocârlie, privighetoare)

    Scrieți următoarele două soluții generate imediat după (ciocârlie, privighetoare, scatiu).

    Vezi rezolvarea

    Răspunsul din barem: (ciocârlie, scatiu) (mierlă, scatiu)

    Păsările se iau în ordinea din mulțime: 1 cinteză, 2 ciocârlie, 3 mierlă, 4 privighetoare, 5 scatiu. Se generează submulțimi cu cel puțin două păsări, în ordine crescătoare a indicilor, sărind peste cele care au și mierla, și privighetoarea.

    După (ciocârlie, privighetoare, scatiu) — adică 2,4,5 — s-au epuizat grupurile care încep cu ciocârlie și conțin privighetoare. Urmează, în ordine:

    1. (ciocârlie, scatiu) — adică 2,5 2. (mierlă, scatiu) — adică 3,5, primul grup care începe cu mierla

    Între ele nu mai încape nimic: (mierlă, privighetoare) ar fi respinsă de condiția din enunț.

  6. Exercițiul 3 6p Tipul înregistrare (struct)

    În declararea alăturată, variabilele f și fs memorează în câmpurile a și b numărătorul, respectiv numitorul câte unei fracții.

    Fără a utiliza alte variabile, scrieți o secvență de instrucțiuni care să memoreze în variabila fs fracția obținută prin scăderea din fracția 2020 ₂₀₂₁ a fracției memorate în variabila f.

    struct fractie
          { int a,b;
          } f,fs;
    Vezi rezolvarea

    ``cpp fs.a = 2020 * f.b - 2021 * f.a; fs.b = 2021 * f.b; ``

    Scăderea a două fracții se face aducându-le la același numitor:

    2020/2021 − f.a/f.b = (2020·f.b − 2021·f.a) / (2021·f.b)

    Numărătorul se calculează înaintea numitorului, fiindcă amândouă au nevoie de f.b neatins — dacă ai scrie întâi fs.b, valoarea folosită la numărător ar fi tot cea bună, dar obiceiul de a calcula în ordinea formulei te ferește de greșeli când variabilele se suprapun.

    Cerința spune „fără a utiliza alte variabile”, deci nu se face nicio simplificare și nu se folosește niciun auxiliar: se scriu direct cele două câmpuri ale lui fs.

Subiectul al III-lea

30 de puncte
  1. Exercițiul 1 10p Subprograme

    Subprogramul divPrim are doi parametri:

    • n, prin care primește un număr natural (n∈[2,10^9]);

    • s, prin care furnizează suma divizorilor primi ai lui n care apar la o putere impară în descompunerea în factori primi a acestuia.

    Scrieți definiția completă a subprogramului.

    Exemple: pentru n=360, după apel s=7 (360=2^3∙3^2∙5^1, deci s=2+5), iar pentru n=16, după apel s=0.

    Vezi rezolvarea
    void divPrim(int n, int &s)
    {
        s = 0;
        for (int d = 2; (long long) d * d <= n; d++)
            if (n % d == 0)
            {
                int e = 0;
                while (n % d == 0)
                {
                    n = n / d;
                    e++;
                }
                if (e % 2 == 1)
                    s = s + d;
            }
        if (n > 1)
            s = s + n;
    }
  2. Exercițiul 2 10p Șiruri de caractere

    Scrieți un program C/C++ care citește de la tastatură două numere naturale n și k, apoi n cuvinte, separate prin Enter. Fiecare cuvânt este format din cel mult 10 caractere, numai litere mici ale alfabetului englez, iar numerele citite sunt din intervalul [1,20].

    Programul afișează pe ecran, pe linii separate, primele k cuvinte dintre cele citite pentru care ultima literă este o vocală, sau doar mesajul nu exista dacă nu există k astfel de cuvinte. Se consideră vocale literele:

    1. a
    2. e
    3. i
    4. o
    5. u

    Exemplu: dacă se citesc datele alăturate, se afișează pe ecran:

    5 2
    norii
    cumulus
    pluteau
    pe
    cer

    norii

    pluteau

    Vezi rezolvarea
    #include <iostream>
    #include <cstring>
    using namespace std;
    
    int main()
    {
        int n, k;
        cin >> n >> k;
        char cuv[21][11], gasite[21][11];
        int g = 0;
        for (int i = 0; i < n; i++)
        {
            cin >> cuv[i];
            int l = strlen(cuv[i]);
            char c = cuv[i][l - 1];
            if (strchr("aeiou", c) != NULL && g < k)
            {
                strcpy(gasite[g], cuv[i]);
                g++;
            }
        }
        if (g < k)
        {
            cout << "nu exista";
            return 0;
        }
        for (int i = 0; i < k; i++)
            cout << gasite[i] << '\n';
        return 0;
    }
  3. Exercițiul 3.a 2p Algoritmi eficienți

    Numărul natural a se numește sufix al numărului natural b dacă a este egal cu b sau dacă b se poate obține din a prin alipirea la stânga a unor noi cifre.

    Fișierul bac.txt conține pe prima linie un număr natural x (x∈[100,999]), iar pe a doua linie un șir de cel mult 10^5 numere naturale din intervalul [0,10^9]. Numerele din șir sunt separate prin câte un spațiu. Se cere să se afișeze pe ecran ultimii doi termeni ai șirului, aflați pe poziții consecutive în acesta, care îl au drept sufix pe numărul x. Numerele sunt afișate în ordinea în care apar în șir, separate printr-un spațiu, iar dacă nu există doi astfel de termeni, 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 alăturate, atunci pe ecran se afișează 3210 15210

    210
    3445 210 893210 1245 1210 3210 15210 67120 20210 12

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

    Vezi rezolvarea

    Timp de executare: O(n) · Memorie: O(1)

    Cum x are trei cifre, un termen t îl are pe x drept sufix exact atunci când t % 1000 == x — adică ultimele lui trei cifre sunt chiar x. Nu e nevoie să compar cifră cu cifră.

    Citesc șirul o singură dată, din fișier, și țin minte doar termenul dinainte. La fiecare pas verific dacă și termenul curent, și cel dinainte trec testul; dacă da, rețin perechea, suprascriind-o pe cea găsită mai devreme. Așa, la final rămâne ultima pereche de acest fel — exact ce se cere. Dacă n-am reținut nicio pereche, afișez nu exista.

    Pe exemplul din enunț, perechile vecine bune sunt 210, 893210, apoi 1210, 3210, apoi 3210, 15210; ultima e cea afișată: 3210 15210.

    De ce e eficient: fiecare număr e citit și testat o singură dată, deci timpul e O(n) pentru cele cel mult 10⁵ numere. Memoria e constantă: se rețin termenul dinainte și cele două numere ale răspunsului, niciodată șirul.

  4. Exercițiul 3.b 8p Algoritmi eficienți

    Același algoritm ca la 3.a.

    Fișierul bac.txt conține pe prima linie un număr natural x (x∈[100,999]), iar pe a doua linie un șir de cel mult 10^5 numere naturale din intervalul [0,10^9]. Numerele din șir sunt separate prin câte un spațiu. Se cere să se afișeze pe ecran ultimii doi termeni ai șirului, aflați pe poziții consecutive în acesta, care îl au drept sufix pe numărul x. Numerele sunt afișate în ordinea în care apar în șir, separate printr-un spațiu, iar dacă nu există doi astfel de termeni, 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 alăturate, atunci pe ecran se afișează 3210 15210

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

    Vezi rezolvarea
    #include <fstream>
    #include <iostream>
    using namespace std;
    
    int main()
    {
        ifstream f("bac.txt");
        long long x, t, anterior = -1, a = -1, b = -1;
        f >> x;
        while (f >> t)
        {
            if (t % 1000 == x && anterior % 1000 == x)
            {
                a = anterior;
                b = t;
            }
            anterior = t;
        }
        f.close();
        if (a < 0)
            cout << "nu exista";
        else
            cout << a << " " << b;
        return 0;
    }

Vrei să vezi ce notă ai lua la examen?

Intră în modul simulare: ai cronometru de 3 ore, codul ți se compilează pe loc, iar la final primești nota conform baremului.

Începe simularea3 ore

Ai găsit o problemă sau ai o idee?

Despre ce este vorba?