Hesablamalar genişlənmiş sahədə aparılmalıdır:
Əməliyyat qaydaları:
Toplama
Vurma
Tutaq ki, x = a + b \sqrt{c}. Onda axtarılan məbləğ sonlu həndəsi silsilədir:
Qalır a=x^{n+1} - 1 və b=x-1 arasında Z_p (\sqrt{c}) sahəsində bölməni həyata keçirmək:
Nümunə
Birinci nümunədə
Bu nümunəni formul ilə hesablayacağıq:
İkinci nümunədə
Alqoritmin reallaşdırılması
modpow funksiyası a^k~mod~p dəyərini hesablayır.
long long modpow(long long a, long long k, long long p)
{
long long res = 1;
a %= p;
while (k)
{
if (k & 1) res = res * a % p;
a = a * a % p;
k >>= 1;
}
return res;
}Num strukturu x + y \sqrt{c} formasında rəqəmləri saxlamaq üçün elan edək.
struct Num
{
long long x, y; // x + y*sqrt(c)
};Z_p (\sqrt{c}) sahəsində toplama əməliyyatını reallaşdırırıq. add funksiyası və rəqəmlərinin cəmini qaytarır.
Num add(Num& a, Num& b)
{
Num res;
res.x = (a.x + b.x) % p;
res.y = (a.y + b.y) % p;
return res;
}Z_p (\sqrt{c}) sahəsində çıxma əməliyyatını reallaşdırırıq. sub funksiyası və rəqəmlərinin fərqini qaytarır.
Num sub(Num& a, Num& b)
{
Num res;
res.x = (a.x - b.x + p) % p;
res.y = (a.y - b.y + p) % p;
return res;
}Z_p (\sqrt{c}) sahəsində vurma əməliyyatını reallaşdırırıq. mult funksiyası və rəqəmlərinin hasilini qaytarır.
Num mult(Num& a, Num& b)
{
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;
}pow funksiyası base^n dərəcəsinə yüksəltməni reallaşdırır, burada Z_p (\sqrt{c}) sahəsində olan rəqəmdir.
Num pow(Num base, long long n)
{
Num res = { 1, 0 }; // sahənin vahidi
while (n > 0)
{
if (n & 1)
res = mult(res, base);
base = mult(base, base);
n >>= 1;
}
return res;
}divide funksiyası Z_p (\sqrt{c}) sahəsində bölməni reallaşdırır. O, və rəqəmlərinin bölünməsini qaytarır. Bölmə əks elementin vurulması ilə həyata keçirilir:
Num divide(Num& a, Num& b)
{Tutaq ki, conj = b_x - b_y \sqrt{c}.
Num conj = { b.x, (p - b.y) % p };n = (a_x + a_y \sqrt{c})(b_x - b_y \sqrt{c}) hesablayırıq.
Num n = mult(a, conj);denom = b_x^2 - b_y^2 c hesablayırıq.
long long denom =
((b.x * b.x) % p - ((b.y * b.y) % p * c) % p + p) % p;Əks elementi hesablayırıq və n / denom = n \cdot denom^{-1} qaytarırıq.
long long inv_denom = modpow(denom, p - 2, p); // əks element
return Num((n.x * inv_denom) % p, (n.y * inv_denom) % p);
}Proqramın əsas hissəsi. Giriş məlumatlarını oxuyuruq.
scanf("%lld %lld %lld %lld %lld", &a, &b, &c, &n, &p);Rəqəmi x = a + b \sqrt{c} və sahənin vahidini one = 1 + 0 \sqrt{c} olaraq təyin edirik.
Num x = { a % p, b % p };
Num one = { 1, 0 };num = x^{n+1} - 1, denom = x - 1 hesablayırıq.
Num num = pow(x, n + 1);
num = sub(num, one);
Num denom = sub(x, one);Cavabı res = num / denom = \frac{x^{n+1} - 1}{x - 1} hesablayırıq və çap edirik.
Num res = divide(num, denom);
printf("%lld %lld\n", res.x, res.y);