Modul üzrə sahə#12317

Modul üzrə sahə (Həll təhlili)

\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:

Z_p (\sqrt{c}) = \{ x + y \sqrt{c}~|~x,y \in Z_p\}

Əməliyyat qaydaları:

(x_1 + y_1 \sqrt{c}) + (x_2 + y_2 \sqrt{c}) = (x_1 + x_2 ) + (y_1 + y_2) \sqrt{c}
(x_1 + y_1 \sqrt{c}) \cdot (x_2 + y_2 \sqrt{c}) = (x_1 x_2 + cy_1 y_2) + (x_1 y_2 + x_2 y_1 ) \sqrt{c}

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ə

(2 + \sqrt{5})^2~mod~17 = (4 + 4 \sqrt{5} + 5)~mod~17 = 9 + 4 \sqrt{5}

İkinci nümunəyə baxaq:

(3 + 2 \sqrt{5})^{10}~mod~17

Tutaq ki, x = 3 + 2 \sqrt{5}. Onun qüvvətlərini hesablayaq:

x^2 = (3 + 2 \sqrt{5})^2~mod~17 = (9 + 12 \sqrt{5} + 20)~mod~17 = 12 + 12 \sqrt{5} \\ x^4 = (12 + 12 \sqrt{5})^2~mod~17 = (144 + 288 \sqrt{5} + 720)~mod~17 = 14 + 16 \sqrt{5} \\ x^8 = (14 + 16 \sqrt{5})^2~mod~17 = (196 + 448 \sqrt{5} + 1280)~mod~17 = 14 + 6 \sqrt{5}

İndi nəticəni hesablaya bilərik:

x^{10} = x^8 \cdot x^2 = (14 + 6 \sqrt{5})(12 + 12 \sqrt{5})~mod~17 = \\ (168 + 72 \sqrt{5} + 168 \sqrt{5} + 360)~mod~17 = 1 + 2 \sqrt{5}

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);