Die Aufgabe lautet wie folgt: Geben Sie bei einer positiven Ganzzahl x
und einer Primzahl n > x
die kleinste positive Ganzzahl y
so aus, dass (y * y) mod n = x
. Ein wichtiger Teil dieser Frage ist die unten angegebene Frist, die Brute-Force-Lösungen ausschließt.
Wenn es keinen solchen Wert gibt, y
sollte Ihr Code ausgegeben werden N
.
Testfälle
(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)
Ein- und Ausgabe
Sie können Eingaben vornehmen und Ausgaben auf eine bequeme Weise geben. Wenn Sie nicht ausgeben N
möchten, reicht ein beliebiger Falsey
Wert aus.
Beschränkungen
Ihr Code muss alle Testfälle in weniger als 1 Minute auf einem Standarddesktop beantworten. Dieses Zeitlimit dient nur dazu, Brute-Force-Antworten zu verhindern, und ich erwarte, dass gute Antworten fast sofort ausgeführt werden. Sie dürfen keine Bibliothek oder eingebaute Bibliothek verwenden, die dieses Problem löst oder testet, ob eine Zahl ein quadratischer Rest ist.
1267650600228229401496703205653
selbst verschlüsseln können oder wenn Sie 128-Bit-Unterstützung haben, wie__int128
in gcc. Es gibt auch eine Reihe von 256-Bit-Int-Bibliotheken für verschiedene Sprachen. Schließlich haben viele Sprachen eine beliebige Genauigkeit in der Bibliothek.Antworten:
Pyth,
8382 BytesTestsuite
Dieses Programm implementiert den Tonelli-Shanks-Algorithmus . Ich habe es geschrieben, indem ich der Wikipedia-Seite genau gefolgt bin. Es nimmt als Eingabe
(n, p)
.Das Fehlen einer Quadratwurzel wird durch den folgenden Fehler gemeldet:
Dies ist ein sehr komplexer Code, der im imperativen Stil geschrieben ist, im Gegensatz zu dem allgemeineren funktionalen Stil von Pyth.
Der eine subtile Aspekt von Pyth, den ich verwende, ist
=
, dass, wenn nicht unmittelbar gefolgt von einer Variablen, im Programm nach der nächsten Variablen gesucht wird, dann das Ergebnis des folgenden Ausdrucks dieser Variablen zugewiesen wird und dann dieses Ergebnis zurückgegeben wird. Ich werde während der Erklärung auf die Wikipedia-Seite verweisen: Tonelli-Shanks-Algorithmus , da dies der Algorithmus ist, den ich implementiere.Erläuterung:
A
nimmt eine 2-Tupel als Eingabe, und ordnet die WerteG
undH
bzw. und kehrt seine Eingabe.Q
ist die anfängliche Eingabe.e
Gibt das letzte Element einer Sequenz zurück. Nach diesem AusschnittG
istn
undH
undQ
sindp
.M
definiert eine 2-Eingangsfunktiong
, bei der die EingängeG
und sindH
..^
ist Pyths schnelle modulare Exponentiationsfunktion. Dieses Snippet definiertg
als Exponentiation ModQ
.f
Definiert eine Wiederholung bis zur falschen Schleife und gibt die Anzahl der Iterationen zurück, für die sie ausgeführt wird, angegeben1
als Eingabe. Während jeder Iteration der Schleife teilen wirH
durch 2, setzenH
diesen Wert und prüfen, ob das Ergebnis ungerade ist. Sobald es soweit ist, hören wir auf.K
speichert die Anzahl der Iterationen, die dies dauerte.Eine sehr schwierige Sache ist das
=2;
bisschen.=
sucht im Voraus nach der nächsten Variablen, dieT
alsoT
auf 2 gesetzt ist. InT
einerf
Schleife befindet sich jedoch der Iterationszähler, mit dem wir;
den Wert vonT
aus der globalen Umgebung abrufen. Dies geschieht, um ein paar Bytes Whitespace zu sparen, die sonst zum Trennen der Zahlen benötigt würden.Nach diesem Snippet
K
istS
aus dem Wikipedia-Artikel (Wiki) undH
istQ
aus dem Wiki, undT
ist2
.Jetzt müssen wir einen quadratischen Mod ohne Rückstand finden
p
. Wir werden dies mit dem Euler-Kriterium brachial erzwingen./Q2
ist ,(p-1)/2
da/
Boden Teilung ist, so dassftgT/Q;1
die erste ganze Zahl findet ,T
woT ^ ((p-1)/2) != 1
, wie gewünscht. Denken Sie daran, dass dies;
wiederT
aus der globalen Umgebung stammt, die immer noch 2 ist. Dieses Ergebnis stammtz
aus dem Wiki.Als nächstes
c
müssenz^Q
wir aus dem Wiki erstellen , also wickeln wir das Obige eing ... H
und weisen das Ergebnis zuT
. JetztT
kommtc
aus dem Wiki.Lassen Sie uns das trennen:
~gGH
.~
ist wie=
, gibt aber den ursprünglichen Wert der Variablen zurück, nicht ihren neuen Wert. Somit kehrt es zurückG
, wasn
aus dem Wiki stammt.Dies weist
J
den Wert von zun^((Q+1)/2)
, derR
aus dem Wiki stammt.Nun wird Folgendes wirksam:
Dies weist
G
den Wert zun^Q
, dert
aus dem Wiki stammt.Jetzt haben wir unsere Schleifenvariablen eingerichtet.
M, c, t, R
aus dem wiki sindK, T, G, J
.Der Text der Schleife ist kompliziert, daher werde ich das Leerzeichen so darstellen, wie ich es geschrieben habe:
Zuerst prüfen wir, ob 1
G
ist. Wenn ja, verlassen wir die Schleife.Der nächste Code, der ausgeführt wird, ist:
Hier suchen wir nach dem ersten Wert ,
i
so dassG^(2^i) mod Q = 1
, beginnend bei 1. Das Ergebnis in wird gespeichertK
.Hier nehmen wir den alten Wert von
K
, subtrahieren den neuen Wert vonK
, subtrahieren 1, erhöhen 2 zu dieser Potenz und erhöhen dannT
zu dieser PotenzmodifikationQ
und weisen dann das Ergebnis zuT
. Das machtT
gleichb
aus dem Wiki.Dies ist auch die Zeile, die die Schleife beendet und fehlschlägt, wenn es keine Lösung gibt, da in diesem Fall der neue Wert von
K
gleich dem alten Wert von istK
, 2 auf das erhöht-1
wird und die modulare Exponentiation einen Fehler auslöst.Als nächstes multiplizieren wir
J
mit dem obigen Ergebnis und speichern es zurückJ
, wobei wir es auf dem neuestenR
Stand halten .Dann haben wir Platz
T
und das Ergebnis zurück inT
, EinstellungT
zurück zuc
aus dem Wiki.Dann multiplizieren wir
G
mit diesem Ergebnis, nehmen den ModQ
und speichern das Ergebnis wieder inG
.Und wir beenden die Schleife.
Nachdem die Schleife vorbei ist,
J
ist eine Quadratwurzel vonn
modp
. Um den kleinsten zu finden, verwenden wir den folgenden Code:_BJ
Erstellt die ListeJ
und deren Negation,%
nimmt implizitQ
als zweites Argument und wendet das Standardverhalten von Pyth% ... Q
auf jedes Mitglied der Sequenz an. DannS
sortiert die Liste undh
nimmt sein erstes Mitglied, das Minimum.quelle
Python 2, 166 Bytes
quelle
%timeit Q(1267650600228229401496703204676,1267650600228229401496703205653) 100 loops, best of 3: 2.83 ms per loop
:)SageMath , 93 Bytes
Durch die Reduktion auf ein viel schwierigeres Problem, für das SageMath schnell genug gebaut wurde.
Probieren Sie es auf SageMathCell
quelle
Haskell , 326 Bytes
Normalerweise mag ich Brute-Force-Antworten. Da dies vom Zeitlimit stark abgehalten wird, ist dies der effizienteste Weg, den ich kenne:
Probieren Sie es online!
Ich bin mir sicher, dass dies weiter verbessert werden kann, aber dies sollte vorerst reichen.
quelle
testCases
mit denen aus dem Original TIO ersetzen , es passt auch ohne sie kaum in einen Kommentar.testCases
.