在代码中放置模运算

时间:2015-08-06 05:38:46

标签: python performance python-2.7 math

我一直在尝试解决一个问题,其中解决方案归结为计算

的价值

enter image description here (n + m-2组合m-1)。

这就是我写的。如果答案超出10^9+7,我需要打印my_answer%(10^9+7)

mod_val=10**9+7
current=[int(x) for x in raw_input().strip().split()]
m=current[0]-1
n=current[1]-1
hi,lo=max(m,n),min(m,n)
num_prod=1
den_prod=1
for each in xrange(1,lo+1):
    den_prod=den_prod*each
    num_prod=num_prod*(hi+each)
print (num_prod//den_prod)%mod_val

但是在所有计算完成后,模运算正好在底部。有没有办法我可以在代码之间的某处放置模运算以节省计算或提高性能?

1 个答案:

答案 0 :(得分:3)

背景

  

<强>事实:

     

(m + n)C n =(m + n)! /(n!m!)= (1 / n!)*((m + n)!/ m!)

查看代码:

第1行:den_prod=den_prod*each代表(1 / n!)

第2行:num_prod=num_prod*(hi+each)代表((m + n)!/ m!)的简化形式。

解决方案

关键思想是在for循环中使用模幂运算,然后对结果应用除法模运算。除法运算变为模和逆的乘法。最后,为了计算模逆,我们使用欧拉定理。

def mod_inv (a, b):
    return pow(a, b - 2, b)

mod_val=10**9+7
current=[int(x) for x in raw_input().strip().split()]
m=current[0]-1
n=current[1]-1

hi,lo=max(m,n),min(m,n)
num_prod=1
den_prod=1
for each in xrange(1,lo+1):
    den_prod = (den_prod*each) % mod_val
    num_prod = (num_prod*(hi+each)) % mod_val

print (num_prod * mod_inv(den_prod, mod_val)) % mod_val

性能

我为问题定了3种不同的解决方案。时间5000组合:(5000 C n)其中n从0到4999.

代码1:上面的解决方案

def mod_inv (a, b):
    return pow(a, b - 2, b)

mod_val=10**9+7

hi = 5000
for lo in range(0, hi-1):

    # Code 1
    num_prod=1
    den_prod=1
    for each in xrange(1,lo+1):
        den_prod = (den_prod*each) % mod_val
        num_prod = (num_prod*(hi+each)) % mod_val

    output = (num_prod * mod_inv(den_prod, mod_val)) % mod_val
    # print output

时间1:

real    0m3.607s
user    0m3.594s
sys     0m0.011s

代码2:您提出的解决方案

mod_val=10**9+7

hi = 5000
for lo in range(0, hi-1):

    # Code 2
    test1 = 1
    test2 = 1
    for each in xrange(1,lo+1):
        test1 = (test1*each)
        test2 = (test2*(hi+each))

    test_output = (test2 / test1) % mod_val
    # print test_output

时间安排2:

real    0m25.377s
user    0m25.337s
sys     0m0.027s

代码3:scipy解决方案

from scipy.misc import comb

hi = 5000
for lo in range(0, hi-1):

    # Code 3
    c = comb(hi+lo, lo, exact=True)
    # print c

时间3:

real    0m36.700s
user    0m36.639s
sys     0m0.048s

大输入的API - Lucas定理

def mod_inv (a, b):
    return pow(a, b - 2, b)

def small_nCr (n, r, mod):
    hi = max(r, (n - r))
    lo = min(r, (n - r))
    num_prod=1
    den_prod=1
    for each in range (1, lo + 1):
        den_prod = (den_prod * each) % mod
        num_prod = (num_prod * (hi + each)) % mod
    small_c = (num_prod * mod_inv (den_prod, mod)) % mod
    return small_c

def lucas (n, r, mod):
    c = 1
    while (n > 0 or r > 0):
        ni = n % mod
        ri = r % mod
        if (ri > ni):
            return 0
        c = c * small_nCr (ni, ri, mod)
        n = n / mod
        r = r / mod
    return c

def nCr (n, r, mod):
    return lucas (n, r, mod) % mod

注意:如果模数值不是素数,则可以应用中国剩余定理。

来源:

Modulo properties

Modulo exponentiation

Modular multiplicative inverse function - usage of pow

Lucas Theorem