平方根数


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
因此,排除了不支持大整数数据类型的语言。可惜
Luis Mendo

1
@LuisMendo如果您可以1267650600228229401496703205653自己编写支持或__int128gcc中有128位支持,则不可以。还有许多用于各种语言的256位int库。最后,许多语言都有一个任意精度的int库。

Answers:


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算法。我是紧跟在Wikipedia页面上编写的。它作为输入(n, p)

由以下错误报告缺少平方根:

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

这是非常复杂的高尔夫代码,以命令式风格编写,与更常见的Pyth功能风格相反。

我正在使用的Pyth的一个微妙方面是=,如果没有紧随其后的是变量,则在程序中向前搜索下一个变量,然后将以下表达式的结果分配给该变量,然后返回该结果。在整个解释中,我将参考Wikipedia页面:Tonelli-Shanks算法,因为这是我正在实现的算法。

说明:

=eAQ

A将2元组作为输入,并将值分别分配给GH,然后返回其输入。Q是初始输入。e返回序列的最后一个元素。在此代码段之后,GnHQp

M.^GHQ

M定义2输入函数g,其中输入为GH.^是Pyth的快速模块化求幂函数。此代码段定义g为平均指数mod Q

Kf%=/H=2;1

f定义一个直到虚假循环的重复,并返回其运行的迭代次数,1作为其输入。在循环的每次迭代期间,我们将其除以H2,并设置H为该值,然后检查结果是否为奇数。一旦它,我们停止。K存储此迭代的次数。

一个非常棘手的事情是=2;位。=向前搜索下一个变量,即T,因此T将其设置为2。但是,Tf循环内部是迭代计数器,因此我们可以从全局环境中;获取的值T。这样做是为了节省几个字节的空白,否则将需要使用这些空白来分隔数字。

这个片段后,KS从维基百科的文章(维基),并且HQ从Wiki,并T2

=gftgT/Q;1H

现在,我们需要找到一个二次非残基mod p。我们将使用Euler准则对此进行暴力破解。/Q2(p-1)/2,由于/是地板分裂,使ftgT/Q;1找到的第一个整数T,其中T ^ ((p-1)/2) != 1,根据需要。回想一下,;再拉T从全球环境,这仍然是2这个结果是z从维基。

接下来,需要c从Wiki 创建z^Q,因此将以上内容包装起来,g ... H并将结果分配给T。现在Tc来自维基。

Jg~gGHh/H2

让我们将其分开:~gGH~类似于=,但是返回变量的原始值,而不是新值。因此,它返回G,这是n从所述的wiki。

这将分配J的值n^((Q+1)/2),该值R来自Wiki。

现在,以下生效:

~gGH

这将分配Gn^Q,该值t来自Wiki。

现在,我们已经设置了循环变量。M, c, t, R来自Wiki的是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,然后将其乘以该乘方mod ,然后将结果分配给T。这T等于b来自Wiki。

这也是终止循环并在没有解决方案的情况下失败的那条线,因为在这种情况下,的新值K将等于的旧值K,将2提升到-1,并且模幂将产生错误。

=*J

接下来,我们将J上述结果乘以并存储在中J,保持R更新。

=^T2

然后,我们T将结果平方并存储回,从Wiki T设置Tc

=%*G=^T2Q

然后我们乘以G该结果,将其取为mod Q并将结果存储回中G

;

然后我们终止循环。

循环结束后,Jnmod的平方根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代码,使其给出答案作为输出吗?我现在才得到“ True”。


@Lembik您需要替换testCases为原始TIO中的那些,即使没有它们也几乎无法放入注释中。
与Orjan约翰森

@ØrjanJohansen非常感谢!我用您的代码调整了答案并替换了 testCases
1717年

呵呵,我看到该TIO链接存在一个奇怪的错误-如果单击它,则包含代码,但是运行或从菜单选项获取URL均无效- 如果我从地址栏中复制URL并将其粘贴到不同的标签,则可以使用。
与Orjan约翰森
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.