【问题标题】:Boring Factorials in pythonpython中无聊的阶乘
【发布时间】:2016-04-22 11:00:59
【问题描述】:

我正在尝试理解和解决以下问题:

Sameer 和 Arpit 想要克服对数学的恐惧,因此他们最近一直在练习数学题。阿曼,他们的朋友 一直在帮助他们。但事实上,Sameer 和 Arpit 得到了 厌倦了涉及阶乘的问题。原因是,阶乘 在问题中太容易计算了,因为它们只需要余数 模一些素数,这很容易在线性时间内计算。所以要 让事情变得有趣,阿曼 - 数学家,给他们 一个有趣的任务。他给了他们一个素数P和一个整数N 靠近P,并要求他们找到N!模 P。他问了 T 个这样的问题。

输入:

第一行包含一个整数 T,表示查询的数量。

接下来的 T 行包含 T 个“N P”形式的查询。 (报价为 清晰度)

输出:

精确输出 T 行,包含 N!模 P。

Example
Input:
3

2 5

5 11

21 71

Output:
2

10

6



Constraints:

1 <= T <= 1000

1 < P <= 2*10^9

1 <= N <= 2*10^9


Abs(N-P) <= 1000

现在我为此写了一个解决方案:

def factorial(c):
n1=1
n2=2
num=1
while num!=c:
    n1=(n1)*(n2)
    n2+=1
    num+=1
return n1


for i in range(int(raw_input())):
    n,p=map(int,raw_input().split())
    print factorial(n)%p

但是正如您所看到的,这是一种低效的解决方案,因此我开始寻找比我知道可以使用威尔逊和费米定理解决的更好的解决方案。但我无法理解作者想说什么 他说:

**在数论中,威尔逊定理指出一个自然数 n > 1 是素数当且仅当

现在我们可以这样写:

(p-1)!   ≡  -1 (mod p)

1*2*3*.........*(n-1)*(n)*..............*(p-1)  ≡   -1 (mod p)

n!*(n+1)*...........*(p-1)   ≡   -1 (mod p)

n!  ≡    -1*[(n+1)*...............(p-2)*(p-1)]^-1 (mod p)

let a=[(n+1)*...............(p-2)*(p-1)]

so

n!≡-1*a^-1(mod p)


From Fermat's Theorem:


a^(p-1) ≡ 1(mod p)

multiply both side by a^-1

a^(p-2)  ≡ a^-1(mod p)

now simply we have to find a^(p-2) mod p

**

所以我实现了这个:

def factorial1(n,p):            # to calculate  a=[(n+1)*...............(p-2)*(p-1)]
n0=n+1
n1=n0+1
while n1<=(p-1):
    n0=n1*n0
    n1+=1
return n0
# print nf(2,5)

for i in range(10):
    n,p=map(int,raw_input().split())
    if n>p:
        print 0
    elif n==p-1:
        print p-1
    else:
        print (factorial1(n,p)**(p-2))%p   #a^(p-2) mod p

但从我得到的输出来看,我认为我误解了他写的内容。有人可以告诉我他告诉我要计算什么以及我如何为他所说的内容编写代码。

【问题讨论】:

  • 我想有些人想出一个答案,别担心
  • 希望如此,我挣扎了好久
  • 我正在研究它,但有很多人比我更擅长这个;)

标签: python algorithm


【解决方案1】:

这不是威尔逊定理的直接应用。与它一起使用以下事实:

  • 如果n &gt;= p 那么n! = 0 (mod p)
  • 如果n &lt; p 然后n! = (p-1)!/[(n+1)(n+2)..(p-1)]。现在使用(p-1)! = -1 (mod p) 的事实。剩下的就是modular multiplicative inverse(例如使用extended Euclidean algorithm)的数字n+1, n+2, ... , p-1,从abs(n-p) &lt;= 1000这一事实来看,该数字最多为1000。将(p-1)! = -1 (mod p) 与数字n+1, n+2, ... , p-1 的所有模乘逆运算相乘,即可得到答案。 (正如 John Coleman 指出的那样,您也可以对乘积进行逆运算,而不是逆乘积作为优化)

在你的情况下n=2, p=5(只是看看它是如何工作的)

n! = 2! = 4!/(3*4) = (-1)*2*4 = 2 (mod 5)

# 2 is modular inverse of 3 since 2*3 = 1 (mod 5)
# 4 is modular inverse of 4 since 4*4 = 1 (mod 5)

【讨论】:

  • 与乘法逆运算相比,乘积逆运算更有意义。
  • 顺便说一句,答案很好。
【解决方案2】:

经过长时间的努力,我设法得到了这个解决方案,这在时间限制内给出了正确的输出。我在问题的代码中计算了同样的东西,除了这段代码的最后一行(即)从 p 中减去答案

for i in range(int(raw_input())):
    n,p=map(int,raw_input().split())
    if n>=p:
        print 0%p
    elif n==p-1:
        print p-1
    else:
        n0=n+1
        n1=n0+1
        while n1<=(p-1):
            n0=n1%p*n0%p
            n1+=1
        print  p-pow(n0,(p-2),p) 

【讨论】:

    猜你喜欢
    • 2011-07-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-21
    • 2018-10-22
    相关资源
    最近更新 更多