Число \sqrt{c} ірраціональне, тому обчислювати вираз у дійсних числах немає сенсу: при до 10^{18} це неможливо через точність. Зауважимо, однак, що будь-який цілий степінь числа a + b\sqrt{c} знову має вигляд x + y\sqrt{c}, оскільки \sqrt{c} \cdot \sqrt{c} = c. Таким чином, обчислення слід виконувати в розширеному полі:
Правила операцій:
Додавання
Множення
Після визначення операції множення елементи поля Z_p (\sqrt{c}) можна підносити до степеня стандартним методом швидкого піднесення до степеня за час O(log_2n). Це дозволить обчислити (a + b \sqrt{c})^n~mod~p.
Приклад
У першому прикладі
Розглянемо другий приклад:
Нехай x = 3 + 2 \sqrt{5}. Обчислимо його степені:
Тепер можна обчислити результат:
Реалізація алгоритму
Оголосимо структуру для зберігання числа вигляду x + y \sqrt{c}.
struct Num
{
long long x, y; // x + y*sqrt(c)
};Реалізуємо множення в полі Z_p (\sqrt{c}). Функція mult повертає добуток чисел і .
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 реалізує піднесення до степеня base^n, де — число в полі Z_p (\sqrt{c}).
Num pow(Num base, long long n)
{
Num res = { 1, 0 }; // одиниця поля
while (n > 0)
{
if (n & 1)
res = mult(res, base);
base = mult(base, base);
n >>= 1;
}
return res;
}Основна частина програми. Читаємо вхідні дані.
scanf("%lld %lld %lld %lld %lld", &a, &b, &c, &n, &p);Ініціалізуємо початкове число start = a + b \sqrt{c}.
Num start = { a % p, b % p };Обчислюємо та виводимо відповідь 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);