C(n ^ m)中的指数

时间:2014-01-30 09:20:29

标签: c exponent

http://z-trening.com/tasks.php?show_task=5000000069&lang=uk

#include <stdio.h>

int main(void)
{
    long long o, s, m, i; 
    long long rez = 1;

    scanf("%lld %lld %lld", &o, &s, &m);
    o = o % m;
    for (i = 0; i < s; i++){
        rez = (rez * o) % m;
    }
    printf("%lld", rez);
    return 0;
}

适用于20个任务中的10个。 有没有更快的方法来提高o ^ s?

2 个答案:

答案 0 :(得分:2)

是的,有一种更快的方法:模幂运算。 http://en.wikipedia.org/wiki/Modular_exponentiation

重复乘法(您的算法)以指数时间运行,而模幂运算以多项式时间运行。它的工作原理如下:

比方说,你想要计算A ^ B mod M. 首先,用二进制写B:

B = bn,bn-1,...,b1,b0

这意味着,

B = bn * 2^n + bn-1 * 2^(n-1) + ... + b1 * 2 + b0

在表达式A ^ B中替换它:

A^B = A^(2^n)^bn * A^(2^(n-1))^bn-1 * ... * A^2^b1 * A^b0

可以递归计算A ^(2 ^ n):

A^(2^n) = (A^(2^(n-1)))^2

现在,诀窍是,使用这个身份使用重复的平方模M来计算每个i的A ^(2 ^ i)。乘法和取幂的通常标识也适用于模块化算术,所以这是完全合法的。完整的算法:

input: A,B,M
output: A^B mod M

result = 1
while(B != 0){
    if(B is odd){
        result = result * A mod M
    }
    B = B / 2
    A = A * A mod M
}
return result

答案 1 :(得分:1)

减少计算次数的简单方法是使用等式:

a^(b+c) = a^b*a^c     (1)

(x*y)%z = ((x%z)*(y%z))%z   (2)

可以快速使用这两个等值来计算(o^1)%m(o^2)%m(o^4)%m(o^8)%m...

o2n = (on * on)%m

现在可以通过循环为s中的每个位迭代一次来解决问题,这意味着复杂性已从O(s)减少到O(log(s)

long long s, o;
int m;

// Input s,o,m (code omitted)

int res = 1, on = o%m;  // Assuming int is at least 32 bits
for (i = 0; i < 35; i++) {  // 2^35 is larger than the largest s allowed.
  if (s & 1 << i) {
    res = res * on;
  }
  on = (on*on)%m;
}
printf("%d\n", res);