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?
答案 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);