基础算法-快速幂运算

快速幂AcWing 89. a^b

a a a b b b 次方对 p p p 取模的值。

输入格式

三个整数 a , b , p a,b,p a,b,p ,在同一行用空格隔开。

输出格式

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

数据范围

0 ≤ a , b ≤ 1 0 9 0 \le a,b \le 10^9 0a,b109
1 ≤ p ≤ 1 0 9 1 \le p \le 10^9 1p109

输入样例:

3 2 7

输出样例:

2

快速计算 a k m o d    p a^k\mod p akmodp

  • 实际上是把 k k k表示成二进制 b log k ⋯ b 2 b 1 b 0 b_{\text{log}k}\cdots b_2b_1b_0 blogkb2b1b0,因此 k = b 0 2 2 0 + b 1 2 2 1 + b 2 2 2 2 + ⋯ b log k 2 2 log k k=b_02^{2^0} + b_12^{2^1}+b_22^{2^2}+ \cdots b_{\text{log}k} 2^{2^{\text{log}k}} k=b0220+b1221+b2222+blogk22logk
  • 计算 a k m o d    p = a b 0 2 2 0 + b 1 2 2 1 + b 2 2 2 2 + ⋯ b log k 2 2 log k m o d    p = ( a b 0 2 2 0 m o d    p ) × ( a b 1 2 2 1 m o d    p ) × ⋯ × ( a b log k 2 2 log k m o d    p ) a^k \mod p=a^{b_02^{2^0} + b_12^{2^1}+b_22^{2^2}+ \cdots b_{\text{log}k} 2^{2^{\text{log}k}}} \mod p=(a^{b_0 2^{2^0}}\mod p) \times (a^{b_1 2^{2^1}}\mod p) \times \cdots \times (a^{b_{\text{log}k} 2^{2^{\text{log}k}}}\mod p) akmodp=ab0220+b1221+b2222+blogk22logkmodp=(ab0220modp)×(ab1221modp)××(ablogk22logkmodp)
  • 此外迭代满足如下关系 2 2 i + 1 m o d    p = ( 2 2 i m o d    p ) 2 2^{2^{i+1}} \mod p=(2^{2^{i}} \mod p)^2 22i+1modp=(22imodp)2
  • 中间结果可能会溢出,要强制进行类型转换
  • 时间复杂度 O ( log k ) O(\text{log}k) O(logk)

a b i = a × a × … × a a^{b_i}=a×a×…×a abi=a×a××a,暴力的计算需要O(n)的时间
快速幂使用二进制拆分和倍增思想,仅需要O(Iog)的时间。
对n做二进制拆分,例如, 3 13 = 3 ( 1101 ) 2 = 3 8 ⋅ 3 4 ⋅ 3 1 3^{13}=3^{(1101)_2}=3^8·3^4·3^1 313=3(1101)2=383431
对Q做平方倍增,例如, 3 1 , 3 2 , 3 4 , 3 8 … 3^1,3^2,3^4,3^8… 31,32,34,38
n有logn+1个二进制位,我知道了 a l , a 2 , a 4 , a 8 , , a 2 l o g n a^l,a^2,a^4,a^8,,a^{2logn} al,a2,a4,a8,,a2logn
只需要计算logn+1次乘法就可以了。

这里偷懒就用define int long long 了

代码

#include 

#define int long long
using namespace std;

int qmi(int x, int k, int p) {
    int res = 1;
    while (k) {
        if (k & 1) res = res * x % p;
        x = x * x % p;
        k >>= 1;
    }
    return res % p;
}

signed main() {
#ifndef ONLINE_JUDGE
    freopen("test.in", "r", stdin);
    freopen("test.out", "w", stdout);
#endif
    int a, b, p;
    cin >> a >> b >> p;
    cout << qmi(a, b, p) << endl;
    return 0;
}

龟速乘AcWing 90. 64位整数乘法

题目

https://www.acwing.com/problem/content/description/92/

a a a b b b p p p 取模的值。

输入格式

第一行输入整数 a a a,第二行输入整数 b b b,第三行输入整数 p p p

输出格式

输出一个整数,表示a*b mod p的值。

数据范围

1 ≤ a , b , p ≤ 1 0 18 1 \le a,b,p \le 10^{18} 1a,b,p1018

输入样例:

3
4
5

输出样例:

2

思路

与快速幂的思想一样,把乘法里面的b用二进制拆分,然后变成b个a相加

此外,还可以使用int128进行计算,但是需要注意强制类型转换

代码

#include 

#define int long long
using namespace std;

int mul(int a, int b, int p) {
    int res = 0;
    while (b) {
        if (b & 1) res = (res + a) % p;
        a = (a + a) % p;
        b >>= 1;
    }
    return res;
}

int mul2(int a, int b, int p) {
    __int128 aa = a, bb = b, pp = p;
    __int128 res = aa * bb % pp;
    return (int) res;
}

signed main() {
#ifndef ONLINE_JUDGE
    freopen("test.in", "r", stdin);
    freopen("test.out", "w", stdout);
#endif
    int a, b, p;
    cin >> a >> b >> p;
    cout << mul2(a, b, p);

    return 0;
}

你可能感兴趣的:(ACM-,ICPC,#,基础算法,算法,c++,数据结构)