【问题标题】:last digit of a^b^ca^b^c 的最后一位
【发布时间】:2016-02-19 08:08:30
【问题描述】:

我被这个问题困住了:

给定a、b和c三个 自然数(如 1

我首先想到的是 O(log n) 算法,用于在 n 次方处提高 a。

   int acc=1; //accumulator
   while(n>0) {
        if(n%2==1)
            acc*=a;
        a=a*a;
        n/=2;
    }

显然,一些基本的数学运算可能会有所帮助,例如“最后一位”的东西:

Last_digit(2^n) = Last_digit(2^(n%4))

其中 n%4 是除法 n/4 的余数

简而言之,我尝试将这些结合起来,但我无法走上正轨。

真的很感激一些帮助。

【问题讨论】:

  • 注意,如果你使用费马小定理和中国剩余定理,你应该可以完全减少这个。换句话说,通过一些数学,你应该能够想出一个 O(1) 的算法。
  • 如果您将数字a 提高到越来越大的幂,最后一位数字将开始循环。你能弄清楚如何在不计算所有b^c 的情况下确定你在周期中的哪个位置吗?
  • @scummy 重点(我认为)是 10 = 2*5 和 2,5 是素数。 CRT 可以让您在给定结果 mod 2 和 mod 5 的情况下找到结果 mod 10
  • @JSQuareD 我想过费马的小定理,但没有任何帮助。我需要搜索中国剩余定理。我还没有考虑过 O(1) 解决方案。非常感谢提示。
  • @user2357112 例如,如果 a=2,找到 (b^c)%4 就足够了。这就是你的意思,不是吗?

标签: math exponentiation


【解决方案1】:

问题是b^c 可能非常大。所以你想在使用标准模幂之前减少它。

您可以注意a^(b^c) MOD 10 最多可以有 10 个不同的值。

由于鸽巢原理,会有一个数字p,这样对于一些r

a^r MOD 10 = a^(p+r) MOD 10
p <= 10
r <= 10

这意味着对于任何q

a^r MOD 10 = a^r*a^p MOD 10
           = (a^r*a^p)*a^p MOD 10
           = ...
           = a^(r+q*p) MOD 10

对于任何n = s+r+q*p,您拥有s &lt; p

a^n MOD 10 = a^s*a^(r+q*p) MOD 10
           = a^s*a^r MOD 10 
           = a^((n-r) MOD p)*a^r MOD 10

您可以在前面的等式中替换 n= (b^c)

您将只计算(b^c-r) MOD p 其中p &lt;= 10 这很容易完成,然后计算a^((b^c-r) MOD p)*a^r MOD 10

【讨论】:

    【解决方案2】:

    就像我在我的 cmets 中提到的那样,这实际上与智能算法没有太大关系。使用一些初等数论可以完全减少这个问题。这将产生一个 O(1) 算法。

    中国剩余定理说,如果我们知道某个数 x 模 2 和模 5,我们就知道它模 10。所以求 a^b^c 模 10 可以简化为求 a^b^c 模 2 和 a ^b^c 模 5。费马小定理说,对于任何素数 p,如果 p 不整除 a,则 a^(p-1) = 1 (mod p),所以 a^n = a^(n mod ( p-1)) (mod p)。如果 p 确实除以 a,那么对于任何 n > 0,显然 a^n = 0 (mod p)。请注意,对于任何 n>0,x^n = x (mod 2),所以 a^b^c = a (mod 2).

    剩下的就是找到a^b^c mod 5,这简化为找到b^c mod 4。不幸的是,我们在这里既不能使用中国剩余定理,也不能使用费马小定理。但是,mod 4 b 只有 4 种可能性,所以我们可以单独检查它们。如果我们从 b = 0 (mod 4) 或 b = 1 (mod 4) 开始,那么当然 b^c = b (mod 4)。如果我们有 b = 2 (mod 4),那么很容易看出 b^c = 2 (mod 4) 如果 c = 1,并且 b^c = 0 (mod 4) 如果 c > 1。如果 b = 3 ( mod 4) 如果 c 为偶数,则 b^c = 3,如果 c 为奇数,则 b^c = 1。这给了我们任何 b 和 c 的 b^c (mod 4),然后给了我们 a^b^c (mod 5),所有这些都在恒定时间内。

    最后有了a^b^c = a (mod 2),我们可以用中国剩余定理求a^b^c (mod 10)。这需要 (x (mod 2), y (mod 5)) 和 z (mod 10) 之间的映射。中国剩余定理只告诉我们这个映射是双射的,它没有告诉我们如何找到它。但是,只有 10 个选项,所以这很容易在一张纸上或使用一个小程序完成。一旦我们找到这个映射,我们只需将它存储在一个数组中,我们就可以在 O(1) 中完成整个计算。

    顺便说一下,这将是我的算法在 python 中的实现:

    # this table only  needs to be calculated once
    # can also be hard-coded
    mod2mod5_to_mod10 = [[0 for i in range(5)] for j in range(2)]
    for i in range(10):
        mod2mod5_to_mod10[i % 2][i % 5] = i
    
    [a,b,c] = [int(input()) for i in range(3)]
    
    if a % 5 == 0:
        abcmod5 = 0
    else:
        bmod4 = b % 4
        if bmod4  == 0 or bmod4 == 1:
            bcmod4 = bmod4 
        elif bmod4 == 2:
            if c == 1:
                bcmod4 = 2
            else:
                bcmod4 = 0
        else:
            if c % 2 == 0:
                bcmod4 = 1
            else:
                bcmod4 = 3
    
        abcmod5 = ((a % 5)**bcmod4) % 5
    
    abcmod2 = a % 2
    
    abcmod10 = mod2mod5_to_mod10[abcmod2][abcmod5]
    
    print(abcmod10)
    

    【讨论】:

    • 我的算法是0(20) = O(1) :)
    • @fjardon 哈哈,是的,完全减少是不必要的。然而,它是令人满意的:)
    • 我确实使用了中国定理once
    • @fjardon,无论如何,我们不得不说 JSQuareD 给出了一个巧妙的解决方案,不是吗?
    • @scummy 我给了+1。最后我们做同样的数学运算,但我让我的算法发现你可以用定理计算的值。复杂性是相同的,不变的。
    猜你喜欢
    • 1970-01-01
    • 2015-11-28
    • 1970-01-01
    • 2011-06-13
    • 2020-01-17
    • 1970-01-01
    • 2011-08-01
    • 2015-06-12
    • 2012-01-27
    相关资源
    最近更新 更多