牛客网0x01 基本算法-位运算
【牛客】A. a^b%p
求 a 的 b 次方对 p 取模的值,其中 0 <= a,b,p <= 1 0 9 10^9 109, p>0
输入描述:
三个用空格隔开的整数a,b和p。
输出描述:
一个整数,表示
a
b
a^b
ab
m
o
d
mod
mod
p
p
p 的值。
示例输入
2 3 9
输出
8
题解
简单理解版:
只考虑实现a的b次方:快速幂
计算
a
b
a ^ b
ab,如果把
b
b
b 写成 2 进制,如 13 的二进制 1101,于是 3 号位 、2号位、0号位就都是1,那么就可以得到 13 =
2
3
2^3
23 +
2
2
2^2
22 +
2
1
2^1
21 = 8 + 4 + 1。所以
a
13
a ^{13}
a13 =
a
8
a^8
a8 *
a
4
a^4
a4 *
a
1
a^1
a1。
核心一:
把
b
b
b 转换成二进制,然和将
b
b
b 的二进制数从右到左判断,如果判断为1,则 ans 乘上当前的次方。eg:
3
5
3^5
35->
3
101
3^{101}
3101:第零位表为1,则 ans 就要乘
a
2
0
a^{2^{0}}
a20,然后第一位为0,不操作,第二位为1,ans乘上
a
2
2
a^{2^{2}}
a22。程序中:ans = 1(ans的初始值) *
a
2
0
a^{2^{0}}
a20 (第一次操作) *
a
2
2
a^{2^{2}}
a22(第二次操作)
核心二:
每次循环的时候不管要不要对ans进行操作,都要对 a 进行一次操作,即a = a * a,假如到了第 n 轮循环,此时正在判断 b 的二进制的第 n-1 位是否为1。又因为 a 在第一次进入循环时,为
a
1
a^1
a1 ,即
a
2
0
a^{2^{0}}
a20 ,那么第n次循环就是
a
2
n
−
1
a^{2^{n-1}}
a2n−1,正好 b 正在判断第 n-1 位,此时如果为1,则直接将ans = ans * a 即可。
public class Solution {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
long a, b, p, ans = 1;
a = in.nextLong();
b = in.nextLong();
p = in.nextLong();
//首先可以将a的b次方转化为二进制表示,然后用一个b&1的与运算,判断一下该二进制表示下第i位是否为1,如果为1结果为true,否则为false,
while (b != 0) {
// System.out.println("当前a为:" + a);
// System.out.println("当前b为:" + Long.toString(b, 2));
//b转二进制数,最后一位是1
if ((b % 2 ) != 0) { //或者(b & 1) ==1 //b转为2进制后当前为是1,需要乘上
ans = ans * a ;
// System.out.println("当前ans为:" + ans);
}
a = a * a ;
//b右移一位
b >>= 1;
}
System.out.println(ans % p);
}
}
进阶为了不让大数爆掉,变为快速幂:
import java.util.Scanner;
public class Solution {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
long a, b, p, ans = 1;
a = in.nextLong();
b = in.nextLong();
p = in.nextLong();
//首先可以将a的b次方转化为二进制表示,然后用一个b&1的与运算,判断一下该二进制表示下第i位是否为1,如果为1结果为true,否则为false,
while (b != 0) {
//b转二进制数,最后一位是1
if ((b % 2 ) != 0) { //或者(b & 1) ==1 //b转为2进制后当前为是1,需要乘上
ans = ans * a % p; //取余p是为了防止程序爆掉
}
a = a * a % p; //取余p是为了防止程序爆掉
//b右移一位
b >>= 1;
}
System.out.println(ans % p);
}
}