{"id":"informatyka-2016-maj-matura-rozszerzona/zad/5.5","paper_id":"informatyka-2016-maj-matura-rozszerzona","number":"5.5","points":3,"ptype":"open","subject":"informatyka","category":"matura","year":2016,"month":"maj","level":"rozszerzona","text":"Kontekst - patrz zadanie 5.1.\n\nBiblioteka planuje wprowadzenie zakazu wypożyczania kilku egzemplarzy tego samego tytułu podręcznika studentom mieszkającym w jednym pokoju. Gdy ta zasada będzie obowiązywać, w żadnym pokoju nie powtórzy się żaden tytuł podręcznika.\n\nPodaj, ile byłoby wypożyczonych podręczników, gdyby takie ograniczenie już funkcjonowało.","answer":null,"answer_text":null,"solution":"## Poprawna odpowiedź\n\n**316 podręczników**\n\n## Sposób 1 - analiza problemu\n\n**Reguła:** w jednym pokoju nie może być więcej niż jeden egzemplarz tego samego tytułu. Czyli z każdej trójki `(pokój, tytuł)` zliczamy 1 wypożyczenie (zamiast np. 2-3, gdy 2-3 osób z tego samego pokoju wypożyczyło ten sam podręcznik).\n\n**Studenci SPOZA miasteczka nie mają pokoju** → ich wypożyczenia liczymy WSZYSTKIE (każdy student spoza to \"osobny pokój\").\n\n**Algorytm:**\n1. Dla studentów Z miasteczka: zlicz **unikalne pary (id_pok, tytul)**.\n2. Dla studentów SPOZA miasteczka: zlicz wszystkie ich wypożyczenia.\n3. Suma = wynik.\n\n## Sposób 2 - SQL\n\n```sql\nSELECT\n(\n-- studenci z miasteczka: unikalne pary (pokój, tytuł)\nSELECT COUNT(DISTINCT m.id_pok || '|' || w.tytul)\nFROM wypozyczenia w\nJOIN meldunek m ON w.pesel = m.pesel\n)\n(\n-- studenci spoza miasteczka: wszystkie wypożyczenia\nSELECT COUNT(*)\nFROM wypozyczenia w\nWHERE w.pesel NOT IN (SELECT pesel FROM meldunek)\n) AS razem;\n\n**Alternatywnie - z UNION:**\n```sql\nSELECT COUNT(*) FROM (\nSELECT DISTINCT m.id_pok, w.tytul\nFROM wypozyczenia w\nJOIN meldunek m ON w.pesel = m.pesel\nUNION ALL\nSELECT NULL, w.tytul\nFROM wypozyczenia w\nWHERE w.pesel NOT IN (SELECT pesel FROM meldunek)\n) AS unique_loans;\n\n## Sposób 3 - Python\n\n```python\n# Wczytaj meldunek: pesel -> id_pok\nmeldunek = {}\nwith open('meldunek.txt', encoding='windows-1250') as f:\nnext(f)\nfor linia in f:\ncz = linia.strip().split('\\t')\nif len(cz) >= 2:\nmeldunek[cz[0]] = cz[1]\n\n# Wczytaj wypożyczenia\nwypozyczenia_z_kampusu = set() # zbiór par (id_pok, tytul)\nwypozyczenia_spoza = 0\nwith open('wypozyczenia.txt', encoding='windows-1250') as f:\nnext(f)\nfor linia in f:\ncz = linia.strip().split('\\t')\nif len(cz) >= 3:\npesel, tytul = cz[1], cz[2]\nif pesel in meldunek:\nwypozyczenia_z_kampusu.add((meldunek[pesel], tytul))\nelse:\nwypozyczenia_spoza += 1\n\nrazem = len(wypozyczenia_z_kampusu) + wypozyczenia_spoza\nprint(razem) # 316\n\n## Sposób 4 - arkusz kalkulacyjny\n\n1. Wypożyczenia: dodaj kolumnę D z `=WYSZUKAJ.PIONOWO(B2; meldunek!A:B; 2; FAŁSZ)` (zwraca id_pok lub błąd dla SPOZA).\n2. Dodaj kolumnę E z formułą: `=JEŻELI(JEST.BŁĄD(D2); C2&\"|SPOZA|\"&A2; D2&\"|\"&C2)` - unikalny klucz dla każdego wiersza.\n- Dla SPOZA klucz zawiera nr wypożyczenia (zawsze unikatowy).\n- Dla z miasteczka klucz = id_pok + tytul (powtórki w pokoju mają ten sam klucz).\n3. Liczba unikalnych: `=ILE.NIEPUSTYCH.UNIKATOWYCH(E2:E_end)` → 316.\n\n## Reference informatyczny - DISTINCT + grupowanie\n\n> Reference - `COUNT(DISTINCT )`:\n> - Liczy liczbę **unikalnych** wartości w wyrażeniu.\n> - W większości SQL można konkatenować pola: `COUNT(DISTINCT a || '|' || b)` lub `COUNT(DISTINCT (a, b))` w PostgreSQL.\n> - **Pułapka NULL**: `COUNT(DISTINCT)` ignoruje NULLe.\n>\n> Reference - Pythonowy zbiór `set` z tuple:\n> - `s.add((a, b))` - dodaje krotkę; ZBIÓR przechowuje tylko unikalne.\n> - `len(s)` - liczba unikalnych krotek.\n> - **Wydajność**: O(1) amortyzowane na operację.\n>\n> Reference - Sprytna alternatywa:\n> - Zamiast `(id_pok, tytul)`, klucz dla SPOZA = `(pesel, tytul)` (unikalny per student) - wtedy nie trzeba rozdzielać przypadków.\n\n## Schemat oceniania CKE\n\n> Klucz CKE (zadanie 5.5, max 3 pkt):\n> - **3 pkt** - prawidłowy wynik **316**\n> - **1 pkt** - wynik NIEUWZGLĘDNIAJĄCY studentów spoza kampusu (311)\n> - **0 pkt** - błędna albo brak\n>\n> **Uwaga: NIE PRZYZNAJE SIĘ 2 PUNKTÓW.**\n\n## Typowe pułapki\n\n- **Pominięcie studentów spoza miasteczka** - wynik 311 zamiast 316 (różnica = 5 osób z 5.4, każda z co najmniej 1 wypożyczeniem). **Krytyczne!**\n- **Liczenie tylko `COUNT(*)` na pierwszym JOIN** - to da pełną liczbę wypożyczeń z kampusu, bez deduplikacji.\n- **Pomyłka z dopuszczalną redundancją** - niektórzy uczniowie odejmują wypożyczenia, zamiast policzyć unikalne pary.\n- **Pomylenie pokoju z PESEL** - pokój identyfikuje grupę współlokatorów, NIE jedną osobę.\n- **Sortowanie niepotrzebne** - zadanie pyta o LICZBĘ, nie listę.\n\n## Złożoność obliczeniowa\n\n- Wczytanie meldunek: O(M).\n- Wczytanie wypożyczeń: O(W).\n- Set z parami: O(W) operacji amortyzowanych.\n- **Łącznie: O(M + W).**","image":null,"solution_image":null,"topics":null,"page_from":null,"source":"maturazai","answer_source":null,"answer_text_source":null,"solution_source":"maturazai","text_source":"maturazai","source_label":"Informatyka · Matura · maj 2016 (rozszerzona)","subject_label":"Informatyka","category_label":"Matura","text_html":"<p>Kontekst - patrz zadanie 5.1.</p>\n<p>Biblioteka planuje wprowadzenie zakazu wypożyczania kilku egzemplarzy tego samego tytułu podręcznika studentom mieszkającym w jednym pokoju. Gdy ta zasada będzie obowiązywać, w żadnym pokoju nie powtórzy się żaden tytuł podręcznika.</p>\n<p>Podaj, ile byłoby wypożyczonych podręczników, gdyby takie ograniczenie już funkcjonowało.</p>","solutions":[{"source":"maturazai","label":"maturazai.pl (AI)","kind":"text","html":"<h4>Poprawna odpowiedź</h4>\n<p><strong>316 podręczników</strong></p>\n<h4>Sposób 1 - analiza problemu</h4>\n<p><strong>Reguła:</strong> w jednym pokoju nie może być więcej niż jeden egzemplarz tego samego tytułu. Czyli z każdej trójki <code>(pokój, tytuł)</code> zliczamy 1 wypożyczenie (zamiast np. 2-3, gdy 2-3 osób z tego samego pokoju wypożyczyło ten sam podręcznik).</p>\n<p><strong>Studenci SPOZA miasteczka nie mają pokoju</strong> → ich wypożyczenia liczymy WSZYSTKIE (każdy student spoza to &quot;osobny pokój&quot;).</p>\n<p><strong>Algorytm:</strong></p>\n<ol><li>Dla studentów Z miasteczka: zlicz <strong>unikalne pary (id_pok, tytul)</strong>.</li><li>Dla studentów SPOZA miasteczka: zlicz wszystkie ich wypożyczenia.</li><li>Suma = wynik.</li></ol>\n<h4>Sposób 2 - SQL</h4>\n<p>```sql<br>SELECT<br>(<br>-- studenci z miasteczka: unikalne pary (pokój, tytuł)<br>SELECT COUNT(DISTINCT m.id_pok || &#x27;|&#x27; || w.tytul)<br>FROM wypozyczenia w<br>JOIN meldunek m ON w.pesel = m.pesel<br>)<br>(<br>-- studenci spoza miasteczka: wszystkie wypożyczenia<br>SELECT COUNT(*)<br>FROM wypozyczenia w<br>WHERE w.pesel NOT IN (SELECT pesel FROM meldunek)<br>) AS razem;</p>\n<p><strong>Alternatywnie - z UNION:</strong><br>```sql<br>SELECT COUNT(*) FROM (<br>SELECT DISTINCT m.id_pok, w.tytul<br>FROM wypozyczenia w<br>JOIN meldunek m ON w.pesel = m.pesel<br>UNION ALL<br>SELECT NULL, w.tytul<br>FROM wypozyczenia w<br>WHERE w.pesel NOT IN (SELECT pesel FROM meldunek)<br>) AS unique_loans;</p>\n<h4>Sposób 3 - Python</h4>\n<p>```python</p>\n<h3>Wczytaj meldunek: pesel -&gt; id_pok</h3>\n<p>meldunek = {}<br>with open(&#x27;meldunek.txt&#x27;, encoding=&#x27;windows-1250&#x27;) as f:<br>next(f)<br>for linia in f:<br>cz = linia.strip().split(&#x27;\\t&#x27;)<br>if len(cz) &gt;= 2:<br>meldunek[cz[0]] = cz[1]</p>\n<h3>Wczytaj wypożyczenia</h3>\n<p>wypozyczenia_z_kampusu = set() # zbiór par (id_pok, tytul)<br>wypozyczenia_spoza = 0<br>with open(&#x27;wypozyczenia.txt&#x27;, encoding=&#x27;windows-1250&#x27;) as f:<br>next(f)<br>for linia in f:<br>cz = linia.strip().split(&#x27;\\t&#x27;)<br>if len(cz) &gt;= 3:<br>pesel, tytul = cz[1], cz[2]<br>if pesel in meldunek:<br>wypozyczenia_z_kampusu.add((meldunek[pesel], tytul))<br>else:<br>wypozyczenia_spoza += 1</p>\n<p>razem = len(wypozyczenia_z_kampusu) + wypozyczenia_spoza<br>print(razem) # 316</p>\n<h4>Sposób 4 - arkusz kalkulacyjny</h4>\n<ol><li>Wypożyczenia: dodaj kolumnę D z <code>=WYSZUKAJ.PIONOWO(B2; meldunek!A:B; 2; FAŁSZ)</code> (zwraca id_pok lub błąd dla SPOZA).</li><li>Dodaj kolumnę E z formułą: <code>=JEŻELI(JEST.BŁĄD(D2); C2&amp;&quot;|SPOZA|&quot;&amp;A2; D2&amp;&quot;|&quot;&amp;C2)</code> - unikalny klucz dla każdego wiersza.</li></ol>\n<ul><li>Dla SPOZA klucz zawiera nr wypożyczenia (zawsze unikatowy).</li><li>Dla z miasteczka klucz = id_pok + tytul (powtórki w pokoju mają ten sam klucz).</li></ul>\n<ol><li>Liczba unikalnych: <code>=ILE.NIEPUSTYCH.UNIKATOWYCH(E2:E_end)</code> → 316.</li></ol>\n<h4>Reference informatyczny - DISTINCT + grupowanie</h4>\n<blockquote>Reference - <code>COUNT(DISTINCT )</code>:<br>- Liczy liczbę <strong>unikalnych</strong> wartości w wyrażeniu.<br>- W większości SQL można konkatenować pola: <code>COUNT(DISTINCT a || &#x27;|&#x27; || b)</code> lub <code>COUNT(DISTINCT (a, b))</code> w PostgreSQL.<br>- <strong>Pułapka NULL</strong>: <code>COUNT(DISTINCT)</code> ignoruje NULLe.<br><br>Reference - Pythonowy zbiór <code>set</code> z tuple:<br>- <code>s.add((a, b))</code> - dodaje krotkę; ZBIÓR przechowuje tylko unikalne.<br>- <code>len(s)</code> - liczba unikalnych krotek.<br>- <strong>Wydajność</strong>: O(1) amortyzowane na operację.<br><br>Reference - Sprytna alternatywa:<br>- Zamiast <code>(id_pok, tytul)</code>, klucz dla SPOZA = <code>(pesel, tytul)</code> (unikalny per student) - wtedy nie trzeba rozdzielać przypadków.</blockquote>\n<h4>Schemat oceniania CKE</h4>\n<blockquote>Klucz CKE (zadanie 5.5, max 3 pkt):<br>- <strong>3 pkt</strong> - prawidłowy wynik <strong>316</strong><br>- <strong>1 pkt</strong> - wynik NIEUWZGLĘDNIAJĄCY studentów spoza kampusu (311)<br>- <strong>0 pkt</strong> - błędna albo brak<br><br><strong>Uwaga: NIE PRZYZNAJE SIĘ 2 PUNKTÓW.</strong></blockquote>\n<h4>Typowe pułapki</h4>\n<ul><li><strong>Pominięcie studentów spoza miasteczka</strong> - wynik 311 zamiast 316 (różnica = 5 osób z 5.4, każda z co najmniej 1 wypożyczeniem). <strong>Krytyczne!</strong></li><li><strong>Liczenie tylko <code>COUNT(*)</code> na pierwszym JOIN</strong> - to da pełną liczbę wypożyczeń z kampusu, bez deduplikacji.</li><li><strong>Pomyłka z dopuszczalną redundancją</strong> - niektórzy uczniowie odejmują wypożyczenia, zamiast policzyć unikalne pary.</li><li><strong>Pomylenie pokoju z PESEL</strong> - pokój identyfikuje grupę współlokatorów, NIE jedną osobę.</li><li><strong>Sortowanie niepotrzebne</strong> - zadanie pyta o LICZBĘ, nie listę.</li></ul>\n<h4>Złożoność obliczeniowa</h4>\n<ul><li>Wczytanie meldunek: O(M).</li><li>Wczytanie wypożyczeń: O(W).</li><li>Set z parami: O(W) operacji amortyzowanych.</li><li><strong>Łącznie: O(M + W).</strong></li></ul>"}]}