2059 - porumbei

From Bitnami MediaWiki

Cerința

A venit primăvara și a început sezonul de concursuri pentru porumbei. La un concurs fiecare participant trebuie să trimită câte doi porumbei. Fiecare porumbel are ataşat pe picior un inel care conţine un număr. Într-o noapte, înainte de un concurs, Tavi, un mare pasionat de porumbei, are un vis în care o zână bună îi spune codurile celor doi porumbei pe care, dacă îi va trimite, va câştiga concursul. Cum Tavi este un mare uituc, dimineaţa îşi mai aminteşte doar prima parte a visului în care zâna îi spune 2 numere a şi n. El îşi mai aminteşte că numerele X şi Y (pe care le-a uitat) de pe inelele porumbeilor sunt puse în aşa fel încât rezultatul aX – aY să fie divizibil cu n. X și Y sunt numerele de pe inelele porumbeilor pe care îi va trimite la concurs.

Dându-se doua numere a şi n, să se afişeze cele două numere X şi Y cu Y minim.

Date de intrare

Fișerul porumbei.in are pe prima linie numerele a și n, separate printr-un spațiu.

Date de ieșire

Dacă datele sunt introduse corect, pe ecran se va afișa: "Datele sunt introduse corect." Fișierul porumbei.out conține două numere naturale distincte, în ordine crescătoare și separate printr-un spațiu, ce reprezintă valorile minime ale lui X și Y astfel încât rezultatul a^X – a^Y să fie divizibil cu n.

În cazul în care datele nu respectă restricțiile, se va afișa: "Datele nu corespund restricțiilor impuse.".

Restricţii şi precizări

  • 2 ≤ n ≤ 2.000.000
  • 2 ≤ a ≤ 2.000.000
  • 0 ≤ X < Y

Exemple

Exemplul 1

porumbei.in
4 10
ecran
Datele sunt introduse corect.
porumbei.out
1 3


Exemplul 2

porumbei.in
4 7
ecran
Datele sunt introduse corect.
porumbei.out
0 4

Exemplul 3

porumbei.in
3 5000000
ecran
Datele nu corespund restricțiilor impuse.
porumbei.out



Rezolvare

<syntaxhighlight lang="python" line="1">

  1. 12059 - porumbei

def validate_input(m, n, a):

   """
   Validates the input values for the pigeonhole principle algorithm.
   Args:
       m (int): The value of the base.
       n (int): The value of the modulus.
       a (int): The starting value.
   Raises:
       ValueError: If any of the input values are invalid.
   Returns:
       None.
   """
   if not (2 <= n <= 2000000):
       raise ValueError("Invalid value for n!")
   if not (2 <= a <= 2000000):
       raise ValueError("Invalid value for a!")


def pigeonhole_principle(m, n):

   """
   Implements the pigeonhole principle algorithm for finding the smallest non-negative integers p and q such that
   m^p ≡ m^q (mod n), where 2 <= m, n <= 2,000,000.
   Args:
       m (int): The value of the base.
       n (int): The value of the modulus.
   Returns:
       A tuple containing the values of p and q.
   """
   v = bytearray(262145)  # The vector used to mark the found remainders
   v[1 // 8] = v[1 // 8] | (1 << (1 % 8))  # Mark the remainder 1 as found
   a = 1
   r = 1
   while True:
       r = (r * m) % n
       if v[r // 8] & (1 << (r % 8)) != 0:  # If the bit for the remainder is already set
           q = a  # Then there was a previous remainder equal to r, so we stop
           break
       else:
           v[r // 8] = v[r // 8] | (1 << (r % 8))
       a += 1
   if r == 1:
       p = 0
   else:
       r1 = 1
       for i in range(1, q):
           r1 = (r1 * m) % n
           if r1 == r:
               p = i
               break
   return (p, q)


if __name__ == "__main__":

   try:
       with open("porumbei.in", "r") as f, open("porumbei.out", "w") as g:
           m, n = map(int, f.readline().strip().split())
           a = 2  # Set a to the minimum valid value
           validate_input(m, n, a)  # Validate the input values
           print("Datele sunt introduse corect.")
           p, q = pigeonhole_principle(m, n)  # Run the algorithm
           g.write(f"{p} {q}\n")  # Write the output to file
   except ValueError as e:
       print("Datele nu corespund restricțiilor impuse.")









</syntaxhighlight>

Explicatie

validate_input(m, n, a) Această funcție validează valorile de intrare m, n, și a pentru a se asigura că îndeplinesc restricțiile impuse. Mai exact, funcția verifică dacă n și a sunt între 2 și 2,000,000 inclusiv, iar dacă nu, se ridică o excepție ValueError cu un mesaj corespunzător. Dacă valorile de intrare sunt valabile, funcția nu returnează nimic.

pigeonhole_principle(m, n) Această funcție implementează algoritmul principiului cutiei poștale pentru a găsi cele mai mici numere naturale pozitive p și q astfel încât m^p ≡ m^q (mod n). În primul rând, se inițializează un vector de byte-uri v care va fi folosit pentru a marca resturile găsite. Se marchează restul 1 ca fiind găsit, deoarece (m^0) % n = 1. Apoi, se calculează restul r = (m^1) % n și se marchează ca fiind găsit în vectorul v. Se crește contorul a și se calculează următorul rest r = (m^a) % n. Acest lucru continuă până când se găsește un rest care a mai fost întâlnit anterior. Atunci, se oprește și se returnează perechea (p, q) de valori, unde p este valoarea minimă a lui a astfel încât m^p ≡ r (mod n) și q este valoarea minimă a lui a astfel încât m^q ≡ r (mod n) și q > p.

if __name__ == "__main__": Această condiție verifică dacă script-ul este rulat ca program principal sau este importat ca modul în alt script Python. În acest caz, script-ul este rulat ca program principal. Acest bloc conține citirea datelor de intrare din fișier, apelarea funcției validate_input() pentru a valida datele de intrare și apelarea funcției pigeonhole_principle() pentru a rula algoritmul. În cazul în care datele nu sunt valide, se va ridica o excepție ValueError care va fi prinsă în blocul except.

try-except Aceasta este o structură de control care permite prinderea și gestionarea excepțiilor în Python. În acest cod, folosim try-except pentru a prinde excepțiile ValueError care sunt ridicate de funcția validate_input(). Dacă o excepție ValueError este prinsă, se afișează un mesaj corespunzător.