Il numero \sqrt{c} è irrazionale, quindi calcolare l'espressione in numeri reali non ha senso: per fino a 10^{18} ciò è impossibile per questioni di precisione. Notiamo, tuttavia, che qualsiasi potenza intera del numero a + b\sqrt{c} ha ancora la forma x + y\sqrt{c}, poiché \sqrt{c} \cdot \sqrt{c} = c. Pertanto, i calcoli vanno eseguiti nel campo esteso:
Regole delle operazioni:
Addizione
Moltiplicazione
Dopo aver definito l'operazione di moltiplicazione, gli elementi del campo Z_p (\sqrt{c}) possono essere elevati a potenza con il metodo standard dell'elevamento a potenza veloce in tempo O(log_2n). Questo permette di calcolare (a + b \sqrt{c})^n~mod~p.
Esempio
Nel primo esempio
Consideriamo il secondo esempio:
Sia x = 3 + 2 \sqrt{5}. Calcoliamo le sue potenze:
Ora possiamo calcolare il risultato:
Implementazione dell'algoritmo
Dichiariamo la struttura per memorizzare un numero della forma x + y \sqrt{c}.
struct Num
{
long long x, y; // x + y*sqrt(c)
};Implementiamo la moltiplicazione nel campo Z_p (\sqrt{c}). La funzione mult restituisce il prodotto dei numeri e .
Num mult(Num
{
Num res;
res.x = (a.x * b.x + c * a.y % p * b.y) % p;
res.y = (a.x * b.y + a.y * b.x) % p;
return res;
}La funzione pow implementa l'elevamento a potenza base^n, dove — è un numero nel campo Z_p (\sqrt{c}).
Num pow(Num base, long long n)
{
Num res = { 1, 0 }; // unità del campo
while (n > 0)
{
if (n & 1)
res = mult(res, base);
base = mult(base, base);
n >>= 1;
}
return res;
}Parte principale del programma. Leggiamo i dati in ingresso.
scanf("%lld %lld %lld %lld %lld", &a, &b, &c, &n, &p);Inizializziamo il numero iniziale start = a + b \sqrt{c}.
Num start = { a % p, b % p };Calcoliamo e stampiamo la risposta ans = start^n~mod~p = (a + b \sqrt{c})^n~mod~p.
Num ans = pow(start, n);
printf("%lld %lld\n", ans.x, ans.y);