\sqrt{c} ədədi irrasionaldır, buna görə də ifadəni həqiqi ədədlərdə hesablamaq mənasızdır: 10^{18}-dək olduqda bu, dəqiqliyə görə mümkün deyil. Lakin qeyd edək ki, a + b\sqrt{c} ədədinin istənilən tam qüvvəti yenidən x + y\sqrt{c} formasında olur, çünki \sqrt{c} \cdot \sqrt{c} = c. Beləliklə, hesablamaları genişləndirilmiş sahədə aparmaq lazımdır:
Əməliyyat qaydaları:
Toplama
Vurma
Vurma əməliyyatı müəyyən edildikdən sonra Z_p (\sqrt{c}) sahəsinin elementlərini standart sürətli qüvvətə yüksəltmə metodu ilə O(log_2n) vaxtında qüvvətə yüksəltmək olar. Bu, (a + b \sqrt{c})^n~mod~p ifadəsini hesablamağa imkan verəcək.
Nümunə
Birinci nümunədə
İkinci nümunəyə baxaq:
Tutaq ki, x = 3 + 2 \sqrt{5}. Onun qüvvətlərini hesablayaq:
İndi nəticəni hesablaya bilərik:
Alqoritmin realizasiyası
x + y \sqrt{c} formasında ədədi saxlamaq üçün strukturunu elan edək.
struct Num
{
long long x, y; // x + y*sqrt(c)
};Z_p (\sqrt{c}) sahəsində vurmanı reallaşdıraq. mult funksiyası və ədədlə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 qüvvətə yüksəltməsini reallaşdırır, burada — Z_p (\sqrt{c}) sahəsindəki ədəddir.
Num pow(Num base, long long n)
{
Num res = { 1, 0 }; // meydanın vahidi
while (n > 0)
{
if (n & 1)
res = mult(res, base);
base = mult(base, base);
n >>= 1;
}
return res;
}Proqramın əsas hissəsi. Giriş məlumatlarını oxuyuruq.
scanf("%lld %lld %lld %lld %lld", &a, &b, &c, &n, &p);start = a + b \sqrt{c} başlanğıc ədədini ilkinləşdiririk.
Num start = { a % p, b % p };ans = start^n~mod~p = (a + b \sqrt{c})^n~mod~p cavabını hesablayıb çap edirik.
Num ans = pow(start, n);
printf("%lld %lld\n", ans.x, ans.y);