a^b

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld

题目描述

求 a 的 b 次方对 p 取模的值,其中 0≤a,b,p≤10^9

输入描述:

三个用空格隔开的整数a,b和p。

输出描述:

一个整数,表示a^b mod p的值。

示例1

输入

2 3 9

输出

8

解题思路:

首先看这题是让我们求a的b次方并对结果去余,如果是按照循环去做的话那么肯定时间复杂度O(b)太大了(b最大到1e+9),所以这里就要想办法把时间缩少,既然一个个循环着相乘不行,我们是否可以一次乘多个呢,这里就用到了快速幂的做法了。

时间复杂度:

O(logb)

快速幂知识点:

基于二分的思想,假如b是奇数的时候,那么就有a^b=a*a^b-1,这个时候b-1就是偶数了,假如是偶数的话就是a^b=a^b/2 * a^b/2, 举个例子吧,假如是
2^10 = 2^5 * 2^5;
2^5 = 2 * 2^4;
2^4 = 2^2 * 2^2;
2^2 = 2^1 * 2^1;
2^1 = 2 * 2^0;
所以有些时候偶数的情况就只需要乘它本身就够了,时间复杂度自然少了很多,这样的话2^10只需要5步就可以求出来了,但是循环的话,却需要十次。
在二进制中假如是2^10那么10对应的二进制就是1010,那么1号位,3号位都是1,所以就有了10 = 2^3+2^1=8+2,所以2^10=2^8+2^2。
所以二进制就先初始化ans = 1,用来存放累积的结果,然后判断b的二进制吗末尾是否为一来判断是奇数还是偶数,如果是奇数就乘以a,然后让a平方,并且b右移一位。只要b等于0,就返回ans。

#include <iostream>
#include <cstdio>
using namespace std;
typedef long long ll;
ll QuickPow(ll a, ll b, ll mod) {
    ll ans = 1;
    while (b) {
        if (b & 1) ans = (ans * a) % mod;
        a = (a * a) % mod;
        b >>= 1;
    }
    return ans % mod;
}
int main() {
    ll a, b, p;
    scanf("%lld %lld %lld", &a, &b, &p);
    printf("%lld\n", QuickPow(a, b, p));
    return 0;
}