# PBinfo #3721 – Cochilie – Rezolvare C++

Sursa: Codul lui Andrei
Limbaj: C++
Autor rezolvare: deivid

## Enunț

O matrice se numește cochilie de ordin N, sau mai simplu cochilie, dacă a fost construită în funcție de un număr natural N nenul după următoarea regulă:


Cochilia este formată inițial dintr-un pătrat de latură 1 cu valoarea 1.
Pentru fiecare pas I cu valorile 2, 3, …, N la cochilia deja existentă, se va alătura pe rând la DREAPTA, JOS, STÂNGA, SUS, în mod repetat în această ordine, câte un pătrat în care toate elementele au valoarea I, iar lungimea laturii pătratului nou corespunde cu latura cochiliei la care se lipește.

O cochilie de ordin 5 se formează în 5 pași astfel:



Liniile și coloanele sunt numerotate de sus în jos și de la stânga la dreapta începând cu valoarea 1.

Cerința
Cunoscând valorile numerelor naturale N și P, va trebui să răspundeți la următoarele întrebări:


Ce dimensiuni are cochilia de ordin N?
Ce elemente se află pe linia P a cochiliei de ordin N?

Date de intrare
Pe prima linie din fișierul de intrare cochilie.in se va găsi valoarea C, care poate să aibă una dintre valorile 1 sau 2. 


Dacă valoarea lui C este 1, atunci pe linia următoare se va găsi valoarea lui N.
Dacă valoarea lui C este 2, atunci pe linia următoare se vor găsi valorile lui N și P separate printr-un spațiu.

Date de ieșire
Datele de ieșire se vor afișa pe prima linie a fișierului de ieșire cochilie.out în funcție de valoarea lui C astfel:


Dacă valoarea lui C este 1, atunci se vor afișa NRLIN și NRCOL separate printr-un spațiu, reprezentând numărul de linii, respectiv numărul de coloane ale cochiliei de ordin N.
Dacă valoarea lui C este 2, atunci se vor afișa elementele de pe linia P ale cochiliei de ordin N, separate prin câte un spațiu.

Restricții și precizări

1 < N < 30
Linia P întotdeauna se referă la o linie validă a cochiliei.
Pentru teste în valoare de 8 puncte avem C = 1.
Pentru alte teste în valoare de 36 de puncte avem C = 2 și N ≤ 17.
Pentru alte teste în valoare de 20 de puncte avem C = 2 și P se referă la prima sau ultima linie a cochiliei.
Pentru alte teste în valoare de 36 de puncte avem C = 2 fără alte restricții.

Exemplul 1:
cochilie.in

1 5
cochilie.out

8 5
Explicație
Cochilia de ordin 5 are 8 linii și 5 coloane.

Exemplul 2:
cochilie.in

2
5 6
cochilie.out

4 4 4 1 2
Explicație
Linia a 6-a a cochiliei de ordin 5 este formată din numerele 4 4 4 1 2.

## Cod sursă C++

```cpp
/**
Sursa oficiala de 100 de puncte, fara functii si fara vectori!
Cu drag,
Alexandru
**/
#include <stdio.h>
#define PRINT_MULTIPLES_OF_4 0
#define PRINT_LABEL 1
#define PRINT_OTHER_EVEN 2
#define PRINT_NEWLINE 3
int main() {
    FILE *fin = fopen("cochilie.in", "r");
    FILE *fout = fopen("cochilie.out", "w");
    int c; /// task index
    int n; /// shell order
    int p; /// row number
    fscanf(fin,"%d%d", &c, &n);
    if (c == 2) {
        fscanf(fin,"%d", &p);
    }
    int i, above = 0, previous = 0, current = 1;
    for (i = 2; i <= n; i++) {
        int aux = current;
        current += previous;
        previous = aux;
        if (i % 4 == 1) {
            above += current;
        }
    }
    if (c == 1) {
        if (n % 2 == 0) {
            fprintf(fout,"%d %d\n", current, current + previous);
        } else {
            fprintf(fout,"%d %d\n", current + previous, current);
        }
    } else {
        previous = 0;
        current = 1;
        int label = 1;
        while (label % 2 == 0 || above >= p || p > above + current + previous) {
            label++;
            int aux = current;
            current += previous;
            previous = aux;
            if (label % 4 == 1) {
                above -= current;
            }
        }
        /// label is the only odd number in the output
        /// all even numbers greater than label are to be printed as well
        int phase = PRINT_MULTIPLES_OF_4;
        int k = n / 4 * 4; /// largest multiple of 4 <= n
        while (phase != PRINT_NEWLINE) {
            int toPrint = 0;
            switch (phase) {
            case PRINT_MULTIPLES_OF_4:
                if (k > label) {
                    toPrint = k;
                    k -= 4;
                } else {
                    phase = PRINT_LABEL;
                    toPrint = label;
                    phase = PRINT_OTHER_EVEN;
                    k = label + label % 4; /// smallest multiple of 4 plus 2 > label
                }
                break;
            case PRINT_OTHER_EVEN:
                if (k <= n) {
                    toPrint = k;
                    k += 4;
                } else {
                    phase = PRINT_NEWLINE;
                }
            }
            if (toPrint != 0) {
                previous = 0;
                current = 1;
                for (i = 2; i <= toPrint; i++) {
                    int aux = current;
                    current += previous;
                    previous = aux;
                }
                for (i = 0; i < current; i++) {
                    fprintf(fout,"%d ", toPrint);
                }
            }
        }
    }
    return 0;
}
```

## Resurse

- [Pagina originală](https://codulluiandrei.ro/rezolvari/pbinfo/3721)
- [Sursa C++](https://codulluiandrei.ro/rezolvari/pbinfo/3721/cod.cpp)
- [Sursa pe GitHub](https://raw.githubusercontent.com/codulluiandrei/pbinfo/main/pbinfo-3721/main.cpp)
- [Cursuri de informatică pentru BAC](https://codulluiandrei.ro/academia/info-curs/pachet-cpp/)
