Zadanie jest następujące: Biorąc pod uwagę dodatnią liczbę całkowitą x
i liczbę pierwszą n > x
, wypisz najmniejszą dodatnią liczbę całkowitą y
taką, że (y * y) mod n = x
. Ważną częścią tego pytania jest określony poniżej termin, który wyklucza rozwiązania dotyczące brutalnej siły.
Jeśli nie ma takiej wartości, y
kod powinien zostać wypisany N
.
Przypadki testowe
(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)
Wejście i wyjście
Możesz przyjmować dane wejściowe i przekazywać dane w dowolny dogodny sposób. Jeśli nie lubisz generować danych, zrobi N
to dowolna Falsey
wartość.
Ograniczenia
Twój kod musi odpowiadać na wszystkie przypadki testowe w czasie krótszym niż 1 minuta na standardowym pulpicie. Ten limit czasowy ma jedynie na celu zapobieganie odpowiedziom z użyciem siły brutalnej i oczekuję, że dobre odpowiedzi będą działać niemal natychmiast. Nie możesz używać żadnej biblioteki lub wbudowanego rozwiązania, które rozwiązałoby ten problem lub które sprawdza, czy liczba jest kwadratową resztą.
1267650600228229401496703205653
samodzielnie kodować wsparcie lub masz 128-bitowe wsparcie, takie jak__int128
w gcc. Dostępnych jest również 256-bitowych bibliotek int dla różnych języków. Wreszcie wiele języków ma bibliotekę int o dowolnej precyzji.Odpowiedzi:
Pyth,
8382 bajtówZestaw testowy
Ten program implementuje algorytm Tonelli-Shanksa . Napisałem to, uważnie śledząc stronę Wikipedii. Przyjmuje jako dane wejściowe
(n, p)
.Brak pierwiastka kwadratowego jest zgłaszany przez następujący błąd:
Jest to bardzo misternie golfowy kod, napisany w stylu imperatywnym, w przeciwieństwie do bardziej popularnego stylu funkcjonalnego Pytha.
Jedynym subtelnym aspektem Pytha, którego używam jest to
=
, że jeśli nie następuje bezpośrednio po nim zmienna, szuka w programie następnej zmiennej do przodu, następnie przypisuje wynik następującego wyrażenia do tej zmiennej, a następnie zwraca ten wynik. W całym objaśnieniu będę odwoływał się do strony wikipedii: algorytm Tonelli-Shanksa , ponieważ jest to algorytm, który wdrażam.Wyjaśnienie:
A
trwa 2-krotnego jako wejście i przydziela wartościG
iH
odpowiednio, i zwraca jego wejście.Q
jest początkowym wejściem.e
zwraca ostatni element sekwencji. Po tym fragmencie,G
ton
iH
iQ
sąp
.M
definiuje funkcję 2 wejśćg
, gdzie wejściami sąG
iH
..^
jest szybką modułową funkcją potęgowania Pytha. Ten fragment kodug
oznacza mod potęgowaniaQ
.f
definiuje powtarzanie aż do fałszywej pętli i zwraca liczbę iteracji, dla których działa, podane1
jako dane wejściowe. Podczas każdej iteracji pętli dzielimyH
przez 2, ustawiamyH
na tę wartość i sprawdzamy, czy wynik jest nieparzysty. Kiedy to nastąpi, przestajemy.K
przechowuje liczbę wykonanych iteracji.Jedną z bardzo trudnych rzeczy jest
=2;
nieco.=
wyszukiwania do przodu do następnej zmiennej, która jestT
, takT
jest ustawiony na 2. JednakżeT
wewnątrzf
pętli licznik iteracji, więc używamy;
, aby uzyskać wartośćT
z globalnym środowisku. Ma to na celu zaoszczędzenie kilku bajtów białych znaków, które w innym przypadku byłyby potrzebne do oddzielenia liczb.Po tym fragmencie
K
pochodziS
z artykułu w Wikipedii (wiki) iH
pochodziQ
z wiki iT
jest2
.Teraz musimy znaleźć kwadratowy mod bez pozostałości
p
. Wymusimy to brutalnie, stosując kryterium Eulera./Q2
to(p-1)/2
, ponieważ/
jest podłogą podziału, takftgT/Q;1
znajdzie Pierwsza liczbaT
w którymT ^ ((p-1)/2) != 1
, zgodnie z życzeniem. Przypomnij sobie, że;
ponownie ściągaT
z globalnego środowiska, które wciąż ma 2. Ten wynik pochodziz
z wiki.Następnie, aby utworzyć
c
z wiki, potrzebujemyz^Q
, więc zawijamy powyższeg ... H
i przypisujemy wynikT
. TerazT
jestc
z wiki.Załóżmy oddzielić to:
~gGH
.~
jest podobny=
, ale zwraca oryginalną wartość zmiennej, a nie jej nową wartość. Zwraca więc, żeG
pochodzin
z wiki.To przypisuje
J
wartośćn^((Q+1)/2)
, która pochodziR
z wiki.Teraz obowiązują następujące zasady:
To przypisuje
G
wartośćn^Q
, która pochodzit
z wiki.Teraz mamy ustawione zmienne pętli.
M, c, t, R
z wiki sąK, T, G, J
.Ciało pętli jest skomplikowane, więc przedstawię go z białą spacją, tak jak to napisałem:
Najpierw sprawdzamy, czy
G
jest 1. Jeśli tak, wychodzimy z pętli.Kolejny działający kod to:
Tutaj szukamy pierwszej
i
takiej wartościG^(2^i) mod Q = 1
, zaczynając od 1. Wynik zostaje zapisany wK
.Tutaj bierzemy starą wartość
K
, odejmujemy nową wartośćK
, odejmujemy 1, podnosimy 2 do tej mocy, a następnie podnosimyT
do tej modów mocyQ
, a następnie przypisujemy wynik doT
. ToT
równa sięb
z wiki.Jest to również linia, która kończy pętlę i kończy się niepowodzeniem, jeśli nie ma rozwiązania, ponieważ w takim przypadku nowa wartość
K
będzie równa starej wartościK
, 2 zostanie podniesiona do-1
, a modułowe potęgowanie spowoduje błąd.Następnie mnożymy
J
przez powyższy wynik i przechowujemy go z powrotemJ
,R
aktualizując go.Następnie poprawiamy
T
i zapisujemy wynik z powrotemT
, ustawiając zT
powrotemc
na wiki.Następnie mnożymy
G
przez ten wynik, bierzemy modQ
i zapisujemy wynik z powrotemG
.I kończymy pętlę.
Po zakończeniu pętli
J
pierwiastek kwadratowy zn
modp
. Aby znaleźć najmniejszy, używamy następującego kodu:_BJ
tworzy listęJ
i jej negację,%
domyślnie przyjmujeQ
za swój drugi argument i używa domyślnego zachowania Pytha do zastosowania% ... Q
do każdego elementu sekwencji. NastępnieS
sortuje listę ih
bierze pierwszego członka, minimum.źródło
Python 2, 166 bajtów
źródło
%timeit Q(1267650600228229401496703204676,1267650600228229401496703205653) 100 loops, best of 3: 2.83 ms per loop
:)SageMath , 93 bajty
Przez redukcję do znacznie trudniejszego problemu, dla którego SageMath ma wystarczająco szybkie wbudowane funkcje.
Wypróbuj na SageMathCell
źródło
Haskell , 326 bajtów
Zwykle lubię odpowiedzi na brutalną siłę. Ponieważ termin zdecydowanie mnie odradza, oto najbardziej skuteczny sposób, jaki znam:
Wypróbuj online!
Jestem pewien, że można to jeszcze pograć w golfa, ale na razie powinno to wystarczyć.
źródło
testCases
te z oryginalnego TIO, ledwo mieści się w komentarzu nawet bez nich.testCases
.