快速幂算法的概念
由于“指数爆炸”的现象,当a^b中指数b较大时,不能直接计算得到a ^b的结果,题目中通常会出现取余或求末几位。
模运算的基本法则
(a + b) % p = (a % p + b % p) % p
(a - b) % p = (a % p - b % p ) % p
(a * b) % p = (a % p * b % p) % p
例题1
计算 x^n mod m,2 ≤ x, m ≤ 1000, 0 ≤ n ≤ 2 ^ 31 - 1
思路
由于n太大,直接暴力算会TLE,使用快速幂解决
需要运用到的公式包括
n为偶数时: x ^ n % m = ( (x^n/2 % m)* (x^n/2 % m) )%m
n为奇数时: x^n % m = ( (x% m)* (x^(n-1) % m) )%m
代码
#include<iostream>
using namespace std;
int main() {
int x, n, m;
cin >> x >> n >> m;
int s = 1;
while (n) {
if (n & 1) s = s * x % m;//n&1即判断末位是1
x = x * x % m;
n >>= 1;
}
cout << s << endl;
return 0;
}
注意事项
- n&1: 与运算 , 可以判断n是否为偶数 如果是偶数,n&1返回0;否则返回1,为奇数。(C语言中的与运算需要区别计组中位与:整数a和b按二进制对齐,按位进行与运算)
- n >>= 1表示将n除以2
例题2
求a^b 最后三位数表示的整数
思路
求最后三位整数即求模1000的结果
代码
#include<iostream>
using namespace std;
int main() {
long long base, power;
long long result = 1;
cin >> base >> power;
for (int i = 1; i <= power; i++) {
result = result * base;
result = result % 1000;
}
cout << result << endl;
return 0;
}
扩展:蒙哥马利算法——RSA加密算法的核心
核心:(a * b) % p = (a % p * b % p) % p
注意:
在做ACM题时,经常都会遇到一些比较大的整数。而常用的内置整数类型常常显得太小了:其中long 和 int
范围是[-231,231),即-21474836482147483647。而unsigned范围是[0,2^32),即04294967295。也就是说,常规的32位整数只能够处理40亿以下的数。
那遇到比40亿要大的数怎么办呢?这时就要用到C++的64位扩展了。不同的编译器对64位整数的扩展有所不同。基于ACM的需要,下面仅介绍VC6.0与g++编译器的扩展。
VC6.0的64位整数分别叫做__int64与unsigned __int64,其范围分别是[-2^63,
263)与[0,264),即-92233720368547758089223372036854775807与018446744073709551615(约1800亿亿)。对64位整数的运算与32位整数基本相同,都支持四则运算与位运算等。
蒙哥马利算法代码
#include<iostream>
using namespace std;
int base, power, mod;
int Montgomery() {
int res = 1;
while (power) {
if (power & 1) res = (res * base) % mod;
power>>= 1;
base = (base * base) % mod;
}
return res;
}
int main() {
cin >> base >> power >> mod;
cout << Montgomery() << endl;
return 0;
}