目录
0. 写在前边
某年几月几日,余于家中学算法,为加强理解以记之,故作此文,多不达意,不喜勿喷。
1.应用
顾名思义,即快速求出a的k次方mod p 的结果(其中0 <= a, k, p <= 10^9 ),时间复杂度为O(log k)
2.原理
(本人实力有限,建议自己动手在纸上写一写)
将a^k用二进制的方法表示出来
首先,我们先把a^k mod p 预处理成 a^2^0 mod p, a^2^1 mod p , .... , a^2^logk mod p.
如何预处理呢?
a^2^0 即 a^1 = a^2^0, a^2^1 = (a^2^0)^2, .... , a^2^logk = (a^2^(logk - 1))^2 即,每一个都是上一个数的平方。
那么怎么把 a^k 表示出来呢?
可以把a^k拆成若干前面我们处理出来的部分的幂的和
a^k = a^2^x1 + a^2x2 + ... + a^2^x = a^(2^x1 + 2^x2 + ... + 2^x),再换成二进制就可以了
比如
k 的二进制 = (110110) k = 2^1 + 2^3 + 2^4 + 2^8; (是1的位加上就可以了)。
最后
将每一项 mod p;
举个栗子:
4^5 mod 10;
我们先预处理出 4^2^0 = 4 (mod 10), 4^2^1 = ( (4^2^0)^2 ) = ( 4^2 ) = 6 (mod 10), 4^2^2 = ( (4^2^1)^2 ) = 6^2 = 6 (mod 10), ....
5的二进制为 101 = 2^0 + 2^2;
4^5 = 4^(2^0+2^2) = 4^2^0 * 4^2^2 = 4 * 6 = 4 (mod 10);
核心在于:反复平方。
代码如下:
// a 的 b 次方对 p 取模
int res = 1 % p; //res 为取模后的值,当b为0时,不进入循环,所以直接 mod p;
while(b)
{
if(b & 1) res = res * a % p; //判断二进制第0位是否为1
b >>= 1; //移到第0位
a = a * a % p; //预处理,重复平方
}
3.例题
求 a 的 b 次方对 p 取模的值。
输入格式
三个整数 a,b,p在同一行用空格隔开。
输出格式
输出一个整数,表示
a^b mod p
的值。数据范围
0≤≤a,b≤10^9
1≤p≤10^9输入样例:
3 2 7
输出样例:
2
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
int main()
{
int a, b, p;
cin >> a >> b >> p;
int res = 1 % p;
while (b)
{
if(b & 1) res =(LL)res * a % p; // a的数值达到10^9,会爆int
b >>= 1;
a =(LL)a * a % p;
}
cout << res << endl;
}