首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >中国剩余定理

中国剩余定理
EN

Code Golf用户
提问于 2015-03-22 01:01:10
回答 2查看 4.6K关注 0票数 23

中国剩余定理告诉我们,我们总是可以找到一个在不同素数模下产生任何所需余数的数字。您的目标是编写代码,以便在多项式时间内输出这样的数字。最短代码获胜。

例如,假设我们被赋予了这些约束:

n \equiv 2 \mod 7
n \equiv 4 \mod 5
n \equiv 0 \mod 11

一个解决方案是n=44。第一个约束是满足的,因为44 = 6\times7 + 2,所以44在除以7时有剩余的2,因此是44 \equiv 2 \mod 7。另外两个制约因素也得到了满足。还有其他解决方案,如n=814n=-341

输入

一个非空的对(p_i,a_i)列表,其中每个模p_i是一个不同的素数,而每个目标a_i是范围0 \le a_i < p_i中的一个自然数。您可以以任何方便的形式接受输入;它实际上不必是一对的列表。您可能不会假设输入是排序的。

输出

一个整数n,使每个索引in \equiv a_i \mod p_i。它不一定是最小的这样的值,而且可能是负的。

多项式时间限制

为了防止只尝试n=0, 1, 2, \dots之类的廉价解决方案,您的代码必须在输入长度的多项式时间内运行。注意,输入中的数字m有长度Θ(\log m),因此m本身在长度上不是多项式。这意味着您不能计数到m或执行m次数的操作,但是可以计算值上的算术操作。

您可能不会使用效率低下的输入格式(如一元)来绕过这一问题。

其他禁令

不允许内建做以下操作:实现中国剩余定理、求解方程或因子数。

您可以使用内置查找mods和模块加法,减法,乘法和指数(与自然数指数)。您不能使用其他内置的模块操作,包括模逆、除法和订单查找。

测试用例

这些给出了最小的非负解。你的答案可能不一样。如果直接检查输出是否满足每个约束,可能会更好。

代码语言:javascript
复制
[(5, 3)] 
3

[(7, 2), (5, 4), (11, 0)]
44

[(5, 1), (73, 4), (59, 30), (701, 53), (139, 112)]
1770977011

[(982451653, 778102454), (452930477, 133039003)]
68121500720666070
EN

回答 2

Code Golf用户

发布于 2015-03-22 10:27:51

Ruby,129

同志们,看来Ruby解决方案必须更长一些,因为如果不加载openssl库并进行到OpenSSL::BN的转换,就无法获得模块化幂运算。不过,写起来还是很有趣的:

代码语言:javascript
复制
require("openssl")
z=eval(gets)
x=1
z.map{|a,b|x*=a}
s=0
z.map{|a,b|e=a.to_bn;s+=(x/a).to_bn.mod_exp(e-2,e).to_i*b*x/a}
puts(s)
票数 3
EN

Code Golf用户

发布于 2015-03-24 09:05:42

Python 2,61

代码语言:javascript
复制
n=P=1
for p,a in input():n+=P*(a-n)*pow(P,p-2,p);P*=p
print n

这使用了其他答案使用的产品建设的一个变体。

其思想是在约束上循环,并更新解决方案n以满足当前约束,而不影响前面的约束。为此,我们跟踪到目前为止所见素数的乘积P,并观察到添加P的倍数对任何已经见过的素数都没有任何影响。

因此,我们只需要通过添加正确的n倍数来更改n%p == a以满足P。我们求解系数c

(n + P*c) % p == a

这需要c = (a-n) * P^(-1),其中逆的是模p。正如其他人所指出的,逆可以用Fermat的小定理作为P^(-1) = pow(P,p-2,p)来计算。所以,c = (a-n) * pow(P,p-2,p),我们用n+= P * (a-n) * pow(P,p-2,p)更新n

票数 3
EN
页面原文内容由Code Golf提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codegolf.stackexchange.com/questions/48057

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档