La tâche est la suivante: étant donné un entier positif x
et un nombre premier n > x
, sortez le plus petit entier positif y
tel que (y * y) mod n = x
. Une partie importante de cette question est le délai spécifié ci-dessous qui exclut les solutions de force brute.
S'il n'y a pas une telle valeur, y
votre code devrait sortir N
.
Cas de test
(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)
Entrée et sortie
Vous pouvez prendre une entrée et donner une sortie de la manière qui vous convient. Si vous n'aimez pas sortir, N
n'importe quelle Falsey
valeur fera l'affaire.
Restrictions
Votre code doit répondre à tous les cas de test en moins d'une minute sur un bureau standard. Ce délai est uniquement destiné à empêcher les réponses par force brute et je m'attends à ce que les bonnes réponses s'exécutent presque instantanément. Vous ne pouvez pas utiliser de bibliothèque ou de module intégré qui résout ce problème ou qui teste si un nombre est un résidu quadratique.
1267650600228229401496703205653
vous-même ou si vous avez un support 128 bits comme__int128
dans gcc. Il existe également un certain nombre de bibliothèques int 256 bits pour différentes langues. Enfin, de nombreuses langues ont une bibliothèque int de précision arbitraire.Réponses:
Pyth,
8382 octetsSuite de tests
Ce programme implémente l' algorithme Tonelli-Shanks . Je l'ai écrit en suivant de près la page Wikipedia. Il faut en entrée
(n, p)
.L'absence d'une racine carrée est signalée par l'erreur suivante:
Il s'agit d'un code très complexe, écrit dans le style impératif, par opposition au style fonctionnel plus courant de Pyth.
Le seul aspect subtil de Pyth que j'utilise est celui
=
qui, s'il n'est pas immédiatement suivi d'une variable, recherche dans le programme la variable suivante, puis assigne le résultat de l'expression suivante à cette variable, puis renvoie ce résultat. Je ferai référence tout au long de l'explication à la page wikipedia: algorithme Tonelli-Shanks , car c'est l'algorithme que j'implémente.Explication:
A
prend un tuple à 2 en entrée, attribue les valeurs àG
etH
respectivement, et renvoie son entrée.Q
est l'entrée initiale.e
renvoie le dernier élément d'une séquence. Après cet extrait,G
estn
,H
etQ
estp
.M
définit une fonction à 2 entréesg
, où les entrées sontG
etH
..^
est la fonction d'exponentiation modulaire rapide de Pyth. Cet extrait définitg
comme signifiant le mod d'exponentiationQ
.f
définit une répétition jusqu'à une fausse boucle et renvoie le nombre d'itérations pour lesquelles il s'exécute, donné1
en entrée. À chaque itération de la boucle, nous divisonsH
par 2, réglonsH
sur cette valeur et vérifions si le résultat est impair. Une fois qu'il est, nous nous arrêtons.K
stocke le nombre d'itérations nécessaires.Une chose très délicate est le
=2;
bit.=
recherche à l'avance la variable suivante, qui estT
doncT
définie sur 2. Cependant, à l'T
intérieur d'unef
boucle se trouve le compteur d'itérations, que nous utilisons;
pour obtenir la valeur deT
de l'environnement global. Ceci est fait pour économiser quelques octets d'espace blanc qui seraient autrement nécessaires pour séparer les nombres.Après cet extrait,
K
provientS
de l'article de wikipedia (wiki), etH
estQ
du wiki, et l'T
est2
.Maintenant, nous devons trouver un mod quadratique non résiduel
p
. Nous allons forcer cela en utilisant le critère d'Euler./Q2
est(p-1)/2
, puisque/
est la division au sol,ftgT/Q;1
trouve donc le premier entierT
oùT ^ ((p-1)/2) != 1
, comme vous le souhaitez. Rappelez-vous que;
tire à nouveauT
de l'environnement mondial, qui est toujours 2. Ce résultat estz
du wiki.Ensuite, pour créer à
c
partir du wiki, nous avons besoinz^Q
, donc nous enveloppons ce qui précèdeg ... H
et attribuons le résultat àT
. Maintenant,T
c'estc
du wiki.Séparons ce:
~gGH
.~
est similaire=
, mais renvoie la valeur d'origine de la variable, pas sa nouvelle valeur. Ainsi, il revientG
, qui provientn
du wiki.Cela affecte
J
la valeur den^((Q+1)/2)
, qui provientR
du wiki.Maintenant, ce qui suit prend effet:
Cela affecte
G
la valeurn^Q
, qui provientt
du wiki.Maintenant, nous avons nos variables de boucle configurées.
M, c, t, R
du wiki sontK, T, G, J
.Le corps de la boucle est compliqué, donc je vais le présenter avec les espaces, comme je l'ai écrit:
Tout d'abord, nous vérifions si
G
est 1. Si oui, nous quittons la boucle.Le code suivant qui s'exécute est:
Ici, nous recherchons la première valeur de
i
telle sorte queG^(2^i) mod Q = 1
, à partir de 1. Le résultat est enregistré dansK
.Ici, nous prenons l'ancienne valeur de
K
, soustrayons la nouvelle valeur deK
, soustrayons 1, augmentons 2 à cette puissance, puis augmentonsT
à ce mod de puissanceQ
, puis attribuons le résultat àT
. CelaT
équivaut àb
partir du wiki.C'est également la ligne qui termine la boucle et échoue s'il n'y a pas de solution, car dans ce cas, la nouvelle valeur de
K
sera égale à l'ancienne valeur deK
, 2 sera élevée à la-1
, et l'exponentiation modulaire générera une erreur.Ensuite, nous multiplions
J
par le résultat ci-dessus et le stockons à nouveauJ
, en restant àR
jour.Ensuite, nous corrigeons
T
et stockons le résultat dansT
, enT
revenant auc
wiki.Ensuite, nous multiplions
G
par ce résultat, le prenons modQ
et stockons le résultatG
.Et nous terminons la boucle.
Une fois la boucle terminée,
J
est une racine carrée den
modp
. Pour trouver le plus petit, nous utilisons le code suivant:_BJ
crée la liste deJ
et sa négation,%
prend implicitementQ
comme deuxième argument et utilise le comportement par défaut de Pyth pour s'appliquer% ... Q
à chaque membre de la séquence.S
Trie ensuite la liste eth
prend son premier membre, le minimum.la source
Python 2, 166 octets
la source
%timeit Q(1267650600228229401496703204676,1267650600228229401496703205653) 100 loops, best of 3: 2.83 ms per loop
:)SageMath , 93 octets
Par réduction à un problème beaucoup plus difficile pour lequel SageMath possède des buildins suffisamment rapides.
Essayez-le sur SageMathCell
la source
Haskell , 326 octets
Habituellement, j'aime les réponses par force brute. Comme cela est fortement déconseillé par le délai, voici le moyen le plus efficace que je connaisse:
Essayez-le en ligne!
Je suis sûr que cela peut être approfondi, mais cela devrait faire pour l'instant.
la source
testCases
par ceux du TIO d'origine, il rentre à peine dans un commentaire même sans eux.testCases
.