牛客网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);
}
}