这里有更好的算法吗?

时间:2012-09-02 09:35:55

标签: python algorithm

我正在尝试解决Python中的this问题。注意到只有第一个吻需要交替,任何由于第一个吻而不是链条一部分的吻可以很好地拥抱第二个下一个人,这就是我想出的代码。这只是一个简单的数学计算,没有循环,没有迭代,没有。但我仍然得到一个超时的消息。任何优化它的方法?

import psyco
psyco.full()
testcase = int(raw_input())
for i in xrange(0,testcase):
    n = int(raw_input())
    if n%2:
        m = n/2;
        ans = 2 + 4*(2**m-1);
        ans = ans%1000000007;
        print ans
    else:
        m = n/2 - 1
        ans = 2 + 2**(n/2) + 4*(2**m-1);
        ans = ans%1000000007
        print ans

2 个答案:

答案 0 :(得分:11)

你使用非常大的指数来计算能力,如果结果没有在过程中减少,那么速度非常慢。例如,10**10000000 % 11的简单计算需要创建一个10000000位的数字并采用模11。更好的方法是modular exponentiation,在每次乘法后减少模11并且整数永远不会变大。

Python提供内置的模幂运算。使用pow(a,b,c)计算(a**b) % c

假设你的算法是正确的,我没有验证。

答案 1 :(得分:3)

答案是一个非常简单的递归。 F(1) = 2F(n)我们有两种选择:

  • n = H,然后亲吻其余客人的方式只是F(n-1)
  • n = K,然后亲吻其余客人的方式数量为2 ** k,其中k是公主未被亲吻的剩余客人人数。因为她必须亲吻每一位剩余的客人,k = ceil((n - 1) / 2)

将它们放在一起,我们得到F(n) = F(n - 1) + 2 ** ceil((n - 1) / 2)

我的尝试,包括采取一切mod 1000000007:

from math import ceil

def F(n):
    m = 1000000007
    a = 2
    for i in range(2, n+1):
        a = (a + pow(2, int(ceil((i - 1.0) / 2)), m)) % m
    return a

编辑:已更新(更快,更难以理解!F(1e9)大约需要3分钟):

def F(n):
    m = 1000000007
    a = 2
    z = 1

    for i in xrange(2, n, 2):
        z = (z * 2) % m
        a = (a + z + z) % m

    if (n & 1 == 0):
        z = (z * 2) % m
        a = (a + z) % m

    return a

编辑2:经过进一步思考,我意识到上述情况实际上只是:

F(n) = (1 + 1) + (2 + 2) + (4 + 4) + ... + (2 ** n/2 + 2 ** n/2)
     = 2 * (1 + 2 + 4 + ... + 2 ** n/2)
     = 2 * (2 ** (n/2 + 1) - 1)
     = 2 ** (n/2 + 2) - 2

但如果n是偶数,则最后2 ** n/2只出现一次,所以我们有:

def F(n):
    m = 1000000007
    z = pow(2, n/2, m)

    if (n % 2 == 0):
        return (z * 3 - 2) % m
    else:
        return (z * 4 - 2) % m

哪个运行得快得多! (受pow(x, y, z)的速度限制,我认为是O(lg n)?)

只是因为,这是单行:

def F(n):
    return (pow(2, n/2, 1000000007) * (3 + n % 2) - 2) % 1000000007

结果:

1   => 2
2   => 4
3   => 6
4   => 10
5   => 14
6   => 22
7   => 30
8   => 46
9   => 62
10  => 94
1e6 => 902893650
1e7 => 502879941
1e8 => 251151906
1e9 => 375000001