Квадратний корінь число


13

Завдання полягає в наступному: Враховуючи додатне ціле число xі просте n > x, виведіть найменше додатне ціле число yтаке, що (y * y) mod n = x. Важливою частиною цього питання є обмеження часу, вказане нижче, яке виключає жорстокі рішення.

Якщо такого значення немає, yкод повинен виводитись N.

Тестові справи

(2, 5, N), 
(3, 5, N), 
(4, 5, 2),
(524291, 1048583, N),
(529533, 1048583, N),
(534775, 1048583, 436853),
(540017, 1048583, 73675),
(536870913, 1073741827, 375394238),
(542239622, 1073741827, 267746399),
(547608331, 1073741827, N),
(552977040, 1073741827, 104595351),
(1099511627676, 1099511627791, N),
(1099511627677, 1099511627791, 269691261521),
(1099511627678, 1099511627791, 413834069585),
(1267650600228229401496703204376, 1267650600228229401496703205653, 5312823546347991512233563776),
(1267650600228229401496703204476, 1267650600228229401496703205653, N)
(1267650600228229401496703204576, 1267650600228229401496703205653, N)
(1267650600228229401496703204676, 1267650600228229401496703205653, 79905476259539917812907012931)

Вхід і вихід

Ви можете взяти вклад і дати вихід будь-яким зручним для вас способом. Якщо ви не любите виводити, Nбудь-яке Falseyзначення буде робити.

Обмеження

Ваш код повинен відповідати на всі тестові випадки протягом менш ніж 1 хвилини на звичайному робочому столі. Цей обмежений термін призначений лише для запобігання грубим відповідям, і я очікую, що хороші відповіді почнуть працювати миттєво. Ви не можете використовувати будь-яку бібліотеку або вбудований модуль, який би вирішив цю проблему, або тести, якщо число є квадратичним залишком.


2
Тож мови без підтримки великого цілого типу даних виключаються. Шкода
Луїс Мендо

1
@LuisMendo Не якщо ви можете кодувати підтримку для 1267650600228229401496703205653себе або якщо у вас є 128-бітова підтримка, наприклад, __int128у gcc. Також є декілька 256-бітових бібліотек Int для різних мов. Нарешті, багато мов мають довільну точність бібліотеки int.

Відповіді:


7

Pyth, 83 82 байт

=eAQM.^GHQKf%=/H=2;1=gftgT/Q;1HJg~gGHh/H2WtG=*J=gT^2t-K=Kfq1gG^2T1=%*G=^T2Q;hS%_BJ

Тестовий набір

Ця програма реалізує алгоритм Tonelli-Shanks . Я написав це, уважно переглядаючи сторінку Вікіпедії. Це приймається як вхід (n, p).

Про відсутність квадратного кореня повідомляється наступною помилкою:

TypeError: pow() 3rd argument not allowed unless all arguments are integers

Це дуже хитромудрий код для гольфу, написаний в імперативному стилі, на відміну від більш поширеного функціонального стилю Pyth.

Один найтонший аспект Pyth, який я використовую, це те =, що якщо за ним не одразу слідує змінна, шукає в програмі наступну змінну вперед, а потім присвоює цій змінній результат наступного виразу, а потім повертає цей результат. Я буду посилатися у всьому поясненні на сторінку вікіпедії: Алгоритм Тонеллі-Шенкс , як це алгоритм, який я реалізую.

Пояснення:

=eAQ

Aприймає 2-кортеж як вхід і присвоює значення відповідно Gі, Hвідповідно, повертає свої дані. Q- початковий вхід. eповертає останній елемент послідовності. Після цього фрагмента коду, Gце nі Hта Qє p.

M.^GHQ

Mвизначає функцію введення 2 g, де входи є Gі H. .^- швидка модульна функція експоненції Піта. Цей фрагмент визначає gяк модус експоненції Q.

Kf%=/H=2;1

fвизначає повторення до помилкового циклу і повертає кількість ітерацій, для яких він працює, з урахуванням 1його введення. Під час кожної ітерації циклу ділимо Hна 2, встановлюємо Hце значення і перевіряємо, чи результат непарний. Як тільки це є, ми зупиняємось. Kзберігає кількість повторень, які це взяло.

Одна дуже хитра річ - це =2;біт. =заздалегідь шукає наступну змінну, яка є T, так Tвстановлено 2. Однак Tвсередині fциклу є лічильник ітерації, тому ми використовуємо ;для отримання значення Tз глобального середовища. Це робиться для того, щоб зберегти пару байтів пробілу, які в іншому випадку знадобляться для розділення чисел.

Після цього фрагмента, Kце Sз вікіпедії статті (вікі), і Hце Qз вікі, і Tє 2.

=gftgT/Q;1H

Тепер нам потрібно знайти квадратичний нерезидуальний мод p. Ми будемо грубо застосовувати це за допомогою критерію Ейлера. /Q2є (p-1)/2, оскільки /є floored поділ, тому ftgT/Q;1знаходить перше ціле число Tде T ^ ((p-1)/2) != 1, як бажано. Нагадаємо, що ;знову тягнеться Tіз глобального середовища, якого досі є 2. Цей результат - zіз вікі.

Далі, щоб створити cз вікі, нам потрібно z^Q, тому ми загортаємо все вище g ... Hта призначаємо результат T. Тепер Tце cз вікі.

Jg~gGHh/H2

Давайте виділимо це: ~gGH. ~є як =, але повертає початкове значення змінної, а не її нове значення. Таким чином, вона повертається G, що nз вікі.

Це призначає Jзначення n^((Q+1)/2), яке є Rз вікі.

Тепер набирає чинності наступне:

~gGH

Це призначає Gзначення n^Q, яке є tз вікі.

Тепер у нас створені наші змінні циклу. M, c, t, Rз вікі є K, T, G, J.

Тіло циклу складне, тому я збираюся представити його з пробілом, як я його написав:

WtG
  =*J
    =
      gT^2
        t-
          K
          =Kfq1gG^2T1
  =%*G=^T2Q;

Спочатку перевіряємо, чи Gє 1. Якщо так, виходимо з циклу.

Наступний код, який працює:

=Kfq1gG^2T1

Тут ми шукаємо перше значення iтакого, що G^(2^i) mod Q = 1, починаючи з 1. Результат зберігається в K.

=gT^2t-K=Kfq1gG^2T1

Тут ми беремо старе значення K, віднімаємо нове значення K, віднімаємо 1, піднімаємо 2 до цієї потужності, а потім піднімаємо Tдо цієї модної потужності Q, а потім присвоюємо результат T. Це Tзрівняється bз вікі.

Це також рядок, який закінчує цикл і відмовляється, якщо немає рішення, оскільки в цьому випадку нове значення Kбуде рівним старому значенню K, 2 буде підняте до -1, і модульна експоненція призведе до помилки.

=*J

Далі ми множимо Jна вищенаведений результат і зберігаємо його назад J, постійно Rоновлюючи.

=^T2

Потім ми Tповертаємо квадрат і зберігаємо результат назад T, Tповертаючись до cвікі.

=%*G=^T2Q

Потім ми множимо Gна цей результат, беремо його мод Qі зберігаємо результат назад в G.

;

І закінчуємо цикл.

Після закінчення циклу J- квадратний корінь nмода p. Щоб знайти найменший, ми використовуємо такий код:

hS%_BJ

_BJстворює список Jта його заперечення, %неявно приймає Qза свій другий аргумент і використовує поведінку Pyth за замовчуванням для застосування % ... Qдо кожного члена послідовності. Потім Sсортує список і hбере його першого члена, як мінімум.


11

Python 2, 166 байт

def Q(x,n,a=0):
 e=n/2
 while pow(a*a-x,e,n)<2:a+=1
 w=a*a-x;b=r=a;c=s=1
 while e:
    if e%2:r,s=(r*b+s*c*w)%n,r*c+s*b
    b,c=(b*b+c*c*w)%n,2*b*c;e/=2
 return min(r,-r%n)

%timeit Q(1267650600228229401496703204676,1267650600228229401496703205653) 100 loops, best of 3: 2.83 ms per loop :)

3
Яка чудова відповідь! Ви відновили мою віру в PPCG.

5
Вибачте питання для новачків, але що PPCG? Польська група кодерів Python?
Інженер з зворотним

@ Головоломки програмування @DaveBoltman Гольф та код.
orlp


3

Haskell , 326 байт

Зазвичай мені подобаються грубі відповіді. Оскільки це сильно не відштовхується від часу, ось найефективніший спосіб, про який я знаю:

r p=((\r->min(mod(-r)p)r)$).f p
f p x|p==2=x|q x=f 0 0|mod p 4==3=x&div(p+1)4|let(r,s)=foldl i(p-1,0)[1..t 1o]=m$x&(d$r+1)*(b&d s)where q a=1/=a&o;m=(`mod`p);a&0=1;a&e|even e=m$a&d e^2|0<1=m$(a&(e-1))*a;b=[n|n<-[2..],q n]!!0;i(a,b)_|m(x&d a*b&d b)==p-1=(d a,d b+o)|0<1=(d a,d b);o=d p;t y x|even x=t(y+1)(d x)|0<1=y;d=(`div`2)

Спробуйте в Інтернеті!

Я впевнений, що це можна пограти далі в гольф, але це слід зробити поки.


Чи можете ви змінити код TIO, щоб він давав відповіді як вихід? Я просто отримую "Правду" на даний момент.


@Lembik Вам потрібно замінити testCasesті з оригінального TIO, він ледве вписується в коментар навіть без них.
Ørjan Johansen

@ ØrjanJohansen Дякую велике! Я підкоригував свою відповідь вашим кодом і замінив testCases.
ბიმო

Так, я бачу химерну помилку із цим посиланням TIO - якщо я натискаю на неї, він має код, але не працює і не отримує URL-адресу з параметрів меню, але якщо я скопіюю URL-адресу з адресного рядка і вставити її в інша вкладка, тоді вона працює.
Ørjan Johansen
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.