Acwing 快速幂

1.快速幂

作用:可以快速求出 a k m o d p a^k mod p akmodp的值,时间复杂度是 O ( l o g k ) . O( log k). O(logk).
核心思路:反复平方法
①预处理出: a 2 0 m o d   p 、 a 2 1 m o d   p 、 a 2 2 m o d   p 、 … 、 a 2 log ⁡ 2 k m o d   p 一共 l o g 2 k 个数 对于这预处理出的数,观察可以发现: a 2 1 = ( a 2 0 ) 2 、 a 2 2 = ( a 2 1 ) 2 、 a 2 3 = ( a 2 2 ) 2 、 … 、 a 2 l o g 2 k = ( a 2 l o g 2 k − 1 ) 2 . 即每个数是前面一个数的平方 ②对于 a k ,可将 a k 拆成 a k = a 2 x 1 × a 2 x 2 × ⋯ × a 2 x t = a 2 x 1 + 2 x 2 + ⋯ + 2 x t 可得到 k = 2 x 1 + 2 x 2 + ⋯ + 2 x t  ,即 k 为 l o g 2 k 个数之和 ​那么 a k m o d   p = ( a 2 x 1 m o d   d ) ∗ ( a 2 x 2 m o d   d ) . . . ( a 2 x t m o d   d ) 再由①中得到的每个数是前一个数的平方,故 a k m o d   p = ( a 2 x 1 m o d   d ) ∗ [ ( a 2 x 1 m o d   d ) ] 2 m o d   d   ∗ . . . ∗ ( 前一个结果的平方 m o d   d ) ③对于怎么得到 a k = a 2 x 1 + 2 x 2 + ⋯ + 2 x t ,简单,直接取 k 的二进制数。 如求 4 5 m o d   10 ,则 k = ( 101 ) 2 ,那么 4 5 = 4 ( 101 ) 2 = 4 2 0 × 4 2 2 而 4 2 0 m o d   10 = 4 , 4 2 1 m o d   10 = 4 2 m o d   10 = 6 , 4 2 2 m o d   10 = 6 2 m o d   10 = 6 , ( 这里就体现了后面的结果为前一个结果的平方再取模 ) 得到最终结果即为 4 5 m o d   10 = 4 ∗ 6   m o d   10 = 4 ①预处理出:a^{2^{0}} mod\ p、a^{2^{1}} mod\ p、a^{2^{2}} mod\ p、\dots、a^{2^{\log_{2}{k} }} mod\ p 一共log_{2}{k}个数\\ 对于这预处理出的数,观察可以发现:a^{2^{1}}=(a^{2^{0}})^2、a^{2^{2}}=(a^{2^{1}})^2、a^{2^{3}}=(a^{2^{2}})^2、\dots、a^{2^{log_{2}{k}}}=(a^{2^{log_{2}{k}-1}})^2.\\即每个数是前面一个数的平方\\ ②对于a^{k},可将 a^{k} 拆成 a^{k} = a^{2^{x_{1}}} \times a^{2^{x_{2}}} \times \dots \times a^{2^{x_{t}}} = a^{2^{x_{1}}+2^{x_{2}}+\dots+2^{x_{t}}}\\可得到k=2^{x_{1}}+2^{x_{2}}+\dots+2^{x_{t}}\ ,即k为log_{2}{k}个数之和\\​那么a^{k} mod\ p=(a^{2^{x_{1}}}mod \ d)*(a^{2^{x_{2}}}mod \ d)...(a^{2^{x_{t}}}mod \ d)\\再由①中得到的每个数是前一个数的平方,故a^{k} mod\ p=(a^{2^{x_{1}}}mod \ d)*[(a^{2^{x_{1}}}mod \ d)]^2 mod\ d\ * ...*\\(前一个结果的平方mod\ d)\\\\③对于怎么得到a^{k}=a^{2^{x_{1}}+2^{x_{2}}+\dots+2^{x_{t}}},简单,直接取k的二进制数。\\ \\如求4^5 mod \ 10,则k=(101)_2,那么4^{5}=4^{(101)_{2}}=4^{2^{0}}\times 4^{2^{2}}\\而4^{2^{0}} mod\ 10=4,4^{2^{1}}mod\ 10=4^2 mod \ 10=6,4^{2^{2}}mod\ 10=6^2 mod \ 10=6,\\(这里就体现了后面的结果为前一个结果的平方再取模)\\得到最终结果即为4^5 mod \ 10=4*6 \ mod \ 10=4 预处理出:a20mod pa21mod pa22mod pa2log2kmod p一共log2k个数对于这预处理出的数,观察可以发现:a21=(a20)2a22=(a21)2a23=(a22)2a2log2k=(a2log2k1)2.即每个数是前面一个数的平方对于ak,可将ak拆成ak=a2x1×a2x2××a2xt=a2x1+2x2++2xt可得到k=2x1+2x2++2xt ,即klog2k个数之和那么akmod p=(a2x1mod d)(a2x2mod d)...(a2xtmod d)再由中得到的每个数是前一个数的平方,故akmod p=(a2x1mod d)[(a2x1mod d)]2mod d ...(前一个结果的平方mod d)对于怎么得到ak=a2x1+2x2++2xt,简单,直接取k的二进制数。如求45mod 10,则k=(101)2,那么45=4(101)2=420×422420mod 10=4421mod 10=42mod 10=6422mod 10=62mod 10=6(这里就体现了后面的结果为前一个结果的平方再取模)得到最终结果即为45mod 10=46 mod 10=4

Acwing 875.快速幂

在这里插入图片描述
具体实现代码(详解版):

#include <iostream> 
using namespace std; 

typedef long long LL; 

// 快速幂函数:计算 m^k % p
LL qmi(int m, int k, int p) {
    // res 初始化为 1 % p,确保即使 p == 1 也能正常工作(防止 p = 1 时除 0 错误)
    int res = 1 % p; 
    int t = m; // t 是当前的底数,从 m 开始

    // 当 k 不为 0 时,继续循环
    while (k) {
        // 如果 k 的最低位是 1,意味着当前需要将 t 乘到结果中
        if (k & 1) 
            res = (LL)res * t % p; // 计算 (res * t) % p,并更新 res

        // 无论 k 的最低位是否为 1,都要将 t 平方,并取模 p
        t = (LL)t * t % p;

        // 右移 k,去掉最低位,这相当于将 k 除以 2
        k >>= 1;
    }

    // 返回最终的结果,即 m^k % p
    return res;
}

int main() {
    int n; 
    cin >> n; 
    
    while (n--) {
        int m, k, p;
        cin >> m >> k >> p; 
        cout << qmi(m, k, p) << endl; // 输出 m^k % p 的结果
    }

    return 0;
}

2.快速幂求逆元

Acwing 快速幂求逆元

在这里插入图片描述
实现思路:

  • 由(a/b)mod m恒等a*x mod m===>(b*x) mod m = 1 ,x为b的逆元
  • 结合费马定理(欧拉函数的应用):b与m互质,且m为质数,则b^(m-1) mod m=1;
  • 上面两式结合:得b的逆元b^(m-2),则模m乘法逆元x=b^(m-2)%m本质上就是求快速幂,但多了一个要求:b和m互质
  • 注意:当b和m不互质时,无解;否则必存在逆元

具体实现代码(详解版):

#include <iostream> 
using namespace std; 

typedef long long LL; // 定义 LL 为 long long 类型,用于处理大整数

// 快速幂函数:计算 m^k % p
LL qmi(int m, int k, int p) {
    // res 初始化为 1 % p,确保即使 p == 1 也能正常工作(防止 p = 1 时除 0 错误)
    int res = 1 % p; 
    int t = m; // t 是当前的底数,从 m 开始
    
    // 当 k 不为 0 时,继续循环
    while (k) {
        // 如果 k 的最低位是 1,意味着当前需要将 t 乘到结果中
        if (k & 1) 
            res = (LL)res * t % p; // 计算 (res * t) % p,并更新 res
        
        // 无论 k 的最低位是否为 1,都要将 t 平方,并取模 p
        t = (LL)t * t % p;
        
        // 右移 k,去掉最低位,这相当于将 k 除以 2
        k >>= 1;
    }
    
    // 返回最终的结果,即 m^k % p
    return res;
}

int main() {
    int n; 
    cin >> n; 
    
   
    while (n--) {
        int m, p;
        cin >> m >> p; // 读取基数 m 和模数 p
        
        // 根据费马小定理计算 m 的模逆元,公式为 m^(p-2) mod p
        int res = qmi(m, p - 2, p);
        
        // 检查 m 是否与 p 互质(即 m % p 不为 0)
        if (m % p) 
            cout << res << endl; // 如果互质,输出结果
        else 
            puts("impossible"); // 如果不互质,输出 "impossible"
    }
    
    return 0; 
}

快速幂的应用:
在这里插入图片描述

以下是一个在 Acwing 平台上使用 C++ 实现的快速排序算法示例: ```cpp #include <iostream> using namespace std; // 交换两个元素 void swap(int& a, int& b) { int temp = a; a = b; b = temp; } // 将数组划分为两个子数组,并返回划分点的索引 int partition(int arr[], int low, int high) { int pivot = arr[low]; // 选择第一个元素作为基准值 int i = low, j = high; while (i < j) { while (i < j && arr[j] >= pivot) j--; // 从右向左找第一个小于基准值的元素 while (i < j && arr[i] <= pivot) i++; // 从左向右找第一个大于基准值的元素 if (i < j) swap(arr[i], arr[j]); // 交换找到的两个元素 } swap(arr[low], arr[i]); // 将基准值放到正确的位置上 return i; } // 快速排序递归函数 void quickSort(int arr[], int low, int high) { if (low < high) { int pi = partition(arr, low, high); // 划分点的索引 quickSort(arr, low, pi - 1); // 对划分点的左侧子数组进行排序 quickSort(arr, pi + 1, high); // 对划分点的右侧子数组进行排序 } } int main() { int n; cin >> n; // 输入数组长度 int arr[n]; for (int i = 0; i < n; i++) { cin >> arr[i]; // 输入数组元素 } quickSort(arr, 0, n - 1); for (int i = 0; i < n; i++) { cout << arr[i] << " "; // 输出排序后的数组 } cout << endl; return 0; } ``` 这段代码实现了在 Acwing 平台上进行快速排序。输入首先会读取一个整数 n,表示数组的长度。然后输入 n 个整数作为数组的元素。接下来,使用快速排序算法对这个数组进行排序,并输出排序后的结果。请注意,在 Acwing 平台上提交代码时,需要将代码放入 `int main()` 函数中,且不需要包含额外的输入输出操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值