Zadanie 1. Potęgowanie modulo

Rozważmy operację potęgowania modularnego, stosowaną np. w algorytmie RSA. Liczbę a podnosimy do potęgi x, po czym bierzemy resztę z dzielenia otrzymanej liczby przez ustaloną liczbę M, dzięki czemu otrzymujemy wynik

,

gdzie aM – dodatnie liczby całkowite, x – nieujemna liczba całkowita.

Mówimy wtedy, że równa się b.

Przykład 1

Dla liczymy resztę z dzielenia 25 (czyli 32) przez 7, zatem .

Dla  mamy b=33mod 11=5, natomiast dla wynikiem jest b=102 mod 13=9.

Zapisz w wybranej przez siebie notacji (w postaci pseudokodupseudokodpseudokodu, listy krokówlista krokówlisty kroków lub w wybranym języku programowania) algorytm, który gdy są dane liczby a, x i M, obliczy b=ax mod M. Aby otrzymać maksymalną liczbę punktów, twój algorytm powinien wykonywać operacji arytmetycznych wymienionych w poniższej uwadze.

Uwaga!

W zapisie algorytmu możesz wykorzystać tylko operacje arytmetyczne: dodawanie, odejmowanie, mnożenie, dzielenie, dzielenie całkowite, resztę z dzielenia, oraz porównywanie liczb; instrukcje sterujące i przypisania do zmiennych lub samodzielnie napisane funkcje zawierające wymienione operacje.

Specyfikacja problemu:

Dane:

  • a – liczba całkowita dodatnia

  • x – nieujemna liczba całkowita

  • M – liczba całkowita dodatnia

Wynik:

  • b – nieujemna liczba całkowita o wartości równej

Zadanie zostało opracowane przez Centralną Komisję Egzaminacyjną i pojawiło się w przykładowym arkuszu maturalnym egzaminu z informatyki w formule . Cały arkusz można znaleźć na stronie internetowej CKE.

Rozwiązanie

Pseudokod

Ważne!

W zapisanym za pomocą pseudokodu algorytmie używamy operatorów divmod. Operator div oznacza dzielenie całkowitoliczbowe, a mod – resztę z dzielenia.

Zauważmy, że ograniczenie liczby operacji () wyklucza podnoszenie do potęgi poprzez mnożenie podstawy tyle razy, ile wynosi wykładnik (). W związku z tym skorzystamy z algorytmu szybkiego potęgowania liczbPeGPO00R1algorytmu szybkiego potęgowania liczb.

Zapisujemy początkowe warunki funkcji:

Linia 1. funkcja potęga otwórz nawias okrągły a przecinek x przecinek M zamknij nawias okrągły. Linia 2. wynik ← 1. Linia 3. mnoznik ← a.

W każdym przebiegu pętli będziemy podnosić mnożnik do kwadratu i wykonywać na nim działanie (zgodnie z przechodzeniem na wyższe bity z postaci binarnej) oraz pomniejszać wartość  za pomocą dzielenia całkowitoliczbowego przez . Jeśli bit na danej pozycji jest niezerowy, przemnażamy wynik przez mnożnik i wykonujemy operację :

Linia 1. funkcja potęga otwórz nawias okrągły a przecinek x przecinek M zamknij nawias okrągły. Linia 2. wynik ← 1. Linia 3. mnoznik ← a. Linia 4. dopóki x zamknij nawias ostrokątny 0 wykonuj dwukropek. Linia 5. jeżeli x mod 2 znak równości 1 wykonaj dwukropek. Linia 6. wynik ← wynik asterysk mnoznik mod M. Linia 7. mnoznik ← mnoznik asterysk mnoznik mod M. Linia 8. x ← x div 2.

Po zakończeniu pętli (czyli wymnożeniu dla wszystkich bitów z postaci binarnej
liczby ) zwracamy wynik:

Linia 1. funkcja potęga otwórz nawias okrągły a przecinek x przecinek M zamknij nawias okrągły. Linia 2. wynik ← 1. Linia 3. mnoznik ← a. Linia 4. dopóki x zamknij nawias ostrokątny 0 wykonuj dwukropek. Linia 5. jeżeli x mod 2 znak równości 1 wykonaj dwukropek. Linia 6. wynik ← wynik asterysk mnoznik mod M. Linia 7. mnoznik ← mnoznik asterysk mnoznik mod M. Linia 8. x ← x div 2. Linia 9. zwróc wynik.

Oto rozwiązania w innych notacjach:

Lista kroków

  1. Zainicjuj wynik jako 1.

  2. Zainicjuj mnożnik jako a.

  3. Dopóki x > 0, wykonuj kroki 4 - 7.

  4. Jeżeli x mod 2 = 1, wykonaj krok 5.

  5. Wynik pomnóż przez mnoznik mod M.

  6. Mnożnik pomnóż przez mnoznik mod M.

  7. Podziel całkowicie wynik przez 2.

  8. Zwróć wynik.

C++

Linia 1. int potega otwórz nawias okrągły int a przecinek int x przecinek int M zamknij nawias okrągły otwórz nawias klamrowy. Linia 2. int wynik znak równości 1 średnik. Linia 3. int mnoznik znak równości a średnik. Linia 4. while otwórz nawias okrągły x zamknij nawias ostrokątny 0 zamknij nawias okrągły otwórz nawias klamrowy. Linia 5. if otwórz nawias okrągły x procent 2 znak równości znak równości 1 zamknij nawias okrągły otwórz nawias klamrowy. Linia 6. wynik znak równości wynik asterysk mnoznik procent M średnik. Linia 7. zamknij nawias klamrowy. Linia 8. mnoznik znak równości mnoznik asterysk mnoznik procent M średnik. Linia 9. x znak równości x prawy ukośnik 2 średnik. Linia 10. zamknij nawias klamrowy. Linia 11. return wynik średnik. Linia 12. zamknij nawias klamrowy.

Java

Linia 1. int potega otwórz nawias okrągły int a przecinek int x przecinek int M zamknij nawias okrągły otwórz nawias klamrowy. Linia 2. int wynik znak równości 1 średnik. Linia 3. int mnoznik znak równości a średnik. Linia 4. while otwórz nawias okrągły x zamknij nawias ostrokątny 0 zamknij nawias okrągły otwórz nawias klamrowy. Linia 5. if otwórz nawias okrągły x procent 2 znak równości znak równości 1 zamknij nawias okrągły otwórz nawias klamrowy. Linia 6. wynik znak równości wynik asterysk mnoznik procent M średnik. Linia 7. zamknij nawias klamrowy. Linia 8. mnoznik znak równości mnoznik asterysk mnoznik procent M średnik. Linia 9. x znak równości x prawy ukośnik 2 średnik. Linia 10. zamknij nawias klamrowy. Linia 11. return wynik średnik. Linia 12. zamknij nawias klamrowy.

Python

Linia 1. def potega otwórz nawias okrągły a przecinek x przecinek M zamknij nawias okrągły dwukropek. Linia 2. wynik znak równości 1. Linia 3. mnoznik znak równości a. Linia 4. while x zamknij nawias ostrokątny 0 dwukropek. Linia 5. if x procent 2 znak równości znak równości 1 dwukropek. Linia 6. wynik znak równości wynik asterysk mnoznik procent M. Linia 7. mnoznik znak równości mnoznik asterysk mnoznik procent M. Linia 8. x znak równości x prawy ukośnik prawy ukośnik 2. Linia 9. return wynik.

Schemat oceniania

  • 4 pkt – za poprawny algorytm, w tym:

    • 3 pkt – za poprawne obliczenie potęgi (w tym 1 pkt za warunki początkowe oraz 2 pkt za poprawną konstrukcję pętli z uwzględnieniem parzystości ),

    • 1 pkt – za zwrócenie poprawnego wyniku,

  • 2 pkt – za poprawny algorytm o złożoności większej niż logarytmiczna,

  • 0 pkt – za odpowiedź niepoprawną lub niepełną albo za brak odpowiedzi.

Praca domowa

Na podstawie przedstawionych funkcji napisz na swoim komputerze program w języku, w którym programujesz. Przetestuj rozwiązanie dla wybranych przez siebie danych.

Zadanie 2

W tym zadaniu zajmujemy się algorytmami działającymi na n‑elementowej tablicy liczb całkowitych A[1..n], gdzie n jest dodatnią liczbą całkowitą.

Poniżej zapisano rekurencyjną procedurę W, której parametrem jest liczba całkowita j z przedziału [1, n]:

Linia 1. procedura W otwórz nawias okrągły j zamknij nawias okrągły dwukropek. Linia 2. jeśli j zamknij nawias ostrokątny 1 to. Linia 3. jeśli A otwórz nawias kwadratowy j minus 1 zamknij nawias kwadratowy zamknij nawias ostrokątny A otwórz nawias kwadratowy j zamknij nawias kwadratowy to. Linia 4. v ← A otwórz nawias kwadratowy j zamknij nawias kwadratowy. Linia 5. A otwórz nawias kwadratowy j zamknij nawias kwadratowy ← A otwórz nawias kwadratowy j minus 1 zamknij nawias kwadratowy. Linia 6. A otwórz nawias kwadratowy j minus 1 zamknij nawias kwadratowy ← v. Linia 7. W otwórz nawias okrągły j minus 1 zamknij nawias okrągły.

Oto przykładowa, 10‑elementowa tablica A[1..10] o zawartości [2,4,6,8,10,9,7,5,3,1].

W wybranej przez siebie notacji zapisz nierekurencyjną wersję procedury W.

Uwaga!

W zapisie algorytmu możesz wykorzystać tylko operacje arytmetyczne (dodawanie, odejmowanie, mnożenie, dzielenie, dzielenie całkowite, reszta z dzielenia), instrukcje porównania, instrukcje sterujące i przypisania do zmiennych lub samodzielnie napisane funkcje, wykorzystujące wyżej wymienione operacje.

Zadanie zostało opracowane przez CKE i pojawiło się w informatorze o egzaminie maturalnym z informatyki w formule . Cały arkusz można znaleźć na stronie internetowej Centralnej Komisji Egzaminacyjnej.

Rozwiązanie

Przedstawmy algorytm za pomocą dopuszczonych na egzaminie maturalnym notacji, czyli pseudokodu, listy kroków, a także języków programowania: C++, Java i Python.

Zauważmy, że procedura W ma pewne cechy wspólne z algorytmem sortowania bąbelkowegoPCfvfjgLksortowania bąbelkowego pojedynczego elementu. Jest on zamieniany miejscami z elementem o wcześniejszym indeksie dopóty, dopóki trafi na element mniejszy od siebie. Warunki początkowe procedury pozostają bez zmiany.

Weźmy pod uwagę przykładową tablicę podaną w treści zadania: A[1..10] o zawartości [2,4,6,8,10,9,7,5,3,1].

Jeżeli wywołamy dla niej procedurę W z parametrem 7, otrzymamy:

Linia 1. 2 4 6 7 8 10 9 5 3 1.

Widzimy, że element będący na siódmym miejscu w tablicy, czyli 7, był zamieniany z poprzednim elementem, aż trafił na wartość mniejszą od siebie, czyli 6.

Następnie wywołajmy procedurę z parametrem 9. Otrzymujemy następujący wynik:

Linia 1. 2 3 4 6 7 8 10 9 5 1.

Na dziewiątym miejscu znajdował się element 3. Widzimy, że był on zamieniany z poprzednim elementem, aż trafił na mniejszy od siebie, czyli 2.

Zapiszmy nierekurencyjną wersję procedury W. Tworzymy zmienną pomocniczą i. Dopóki indeks i jest większy od , a elementy na poprzedzających indeksach większe od wartości v, dopóty przesuwamy je w prawo.

Następnie wstawiamy element v w miejsce o tym indeksie, na którym skończyliśmy pętlę.

Linia 1. procedura W otwórz nawias okrągły j zamknij nawias okrągły. Linia 2. jeżeli j zamknij nawias ostrokątny 1 dwukropek. Linia 3. v ← A otwórz nawias kwadratowy j zamknij nawias kwadratowy. Linia 4. i ← j. Linia 5. dopóki i zamknij nawias ostrokątny 1 oraz A otwórz nawias kwadratowy i minus 1 zamknij nawias kwadratowy zamknij nawias ostrokątny v wykonuj dwukropek. Linia 6. A otwórz nawias kwadratowy i zamknij nawias kwadratowy ← A otwórz nawias kwadratowy i minus 1 zamknij nawias kwadratowy. Linia 7. i ← i minus 1. Linia 8. A otwórz nawias kwadratowy i zamknij nawias kwadratowy ← v.

Rozwiązania zapisane za pomocą innych dopuszczonych na egzaminie maturalnym notacji wyglądają następująco:

Lista kroków

  1. Jeżeli j > 1, wykonaj kroki 2‑6.

  2. Zainicjuj v jako A[j].

  3. Zainicjuj i jako j.

  4. Dopóki i > 1 oraz A[i - 1] > v, wykonuj kroki 4 i 5.

  5. Do A[i] przypisz A[i - 1].

  6. Do i przypisz i - 1.

  7. Do A[i] przypisz v.

C++

Linia 1. void W otwórz nawias okrągły int j zamknij nawias okrągły otwórz nawias klamrowy. Linia 2. if otwórz nawias okrągły j zamknij nawias ostrokątny 1 zamknij nawias okrągły otwórz nawias klamrowy. Linia 3. int v znak równości A otwórz nawias kwadratowy j zamknij nawias kwadratowy średnik. Linia 4. int i znak równości j średnik. Linia 5. while otwórz nawias okrągły otwórz nawias okrągły i zamknij nawias ostrokątny 1 zamknij nawias okrągły ampersant ampersant A otwórz nawias kwadratowy i minus 1 zamknij nawias kwadratowy zamknij nawias ostrokątny v zamknij nawias okrągły otwórz nawias klamrowy. Linia 6. A otwórz nawias kwadratowy i zamknij nawias kwadratowy znak równości A otwórz nawias kwadratowy i minus 1 zamknij nawias kwadratowy średnik. Linia 7. i minus znak równości 1 średnik. Linia 8. zamknij nawias klamrowy. Linia 9. A otwórz nawias kwadratowy i zamknij nawias kwadratowy znak równości v średnik. Linia 10. zamknij nawias klamrowy. Linia 11. zamknij nawias klamrowy.

Java

Linia 1. void W otwórz nawias okrągły int j zamknij nawias okrągły otwórz nawias klamrowy. Linia 2. if otwórz nawias okrągły j zamknij nawias ostrokątny 1 zamknij nawias okrągły otwórz nawias klamrowy. Linia 3. int v znak równości A otwórz nawias kwadratowy j zamknij nawias kwadratowy średnik. Linia 4. int i znak równości j średnik. Linia 5. while otwórz nawias okrągły otwórz nawias okrągły i zamknij nawias ostrokątny 1 zamknij nawias okrągły ampersant ampersant A otwórz nawias kwadratowy i minus 1 zamknij nawias kwadratowy zamknij nawias ostrokątny v zamknij nawias okrągły otwórz nawias klamrowy. Linia 6. A otwórz nawias kwadratowy i zamknij nawias kwadratowy znak równości A otwórz nawias kwadratowy i minus 1 zamknij nawias kwadratowy średnik. Linia 7. i minus znak równości 1 średnik. Linia 8. zamknij nawias klamrowy. Linia 9. A otwórz nawias kwadratowy i zamknij nawias kwadratowy znak równości v średnik. Linia 10. zamknij nawias klamrowy. Linia 11. zamknij nawias klamrowy.

Python

Linia 1. def W otwórz nawias okrągły j zamknij nawias okrągły dwukropek. Linia 2. if j zamknij nawias ostrokątny 1 dwukropek. Linia 3. v znak równości A otwórz nawias kwadratowy j zamknij nawias kwadratowy. Linia 4. i znak równości j. Linia 5. while i zamknij nawias ostrokątny 1 and A otwórz nawias kwadratowy i minus 1 zamknij nawias kwadratowy zamknij nawias ostrokątny v dwukropek. Linia 6. A otwórz nawias kwadratowy i zamknij nawias kwadratowy znak równości A otwórz nawias kwadratowy i minus 1 zamknij nawias kwadratowy. Linia 7. i minus znak równości 1. Linia 8. A otwórz nawias kwadratowy i zamknij nawias kwadratowy znak równości v.

Schemat oceniania

  • 3 pkt – poprawny algorytm w tym:

    • 1 pkt – za poprawne inicjowanie zmiennych,

    • 1 pkt – za poprawną konstrukcję pętli,

    • 1 pkt – za poprawne instrukcje w pętli,

  • 0 pkt – za niepoprawną odpowiedź albo brak odpowiedzi.

Praca domowa

Na podstawie przedstawionych funkcji napisz na swoim komputerze program w języku, w którym programujesz. Przetestuj rozwiązanie dla wybranych przez siebie danych.

Słownik

lista kroków
lista kroków

jeden ze sposobów zapisu algorytmu; jest to numerowana instrukcja postępowania

pseudokod
pseudokod

jedna z metod zapisywania algorytmów; pseudokod jest zapisem uniwersalnym, w przypadku którego nie używa się słów kluczowych języków programowania; nie istnieją sformalizowane reguły zapisu pseudokodu – ma być on przejrzysty i zrozumiały, a do jego odczytania nie może być wymagana znajomość języków programowania