P5431 【模板】乘法逆元 2

【模板】乘法逆元 2

题目描述

给定 n n n 个正整数 a i a_i ai ,求它们在模 p p p 意义下的乘法逆元。

由于输出太多不好,所以将会给定常数 k k k,你要输出的答案为:
∑ i = 1 n k i a i \sum\limits_{i=1}^n\frac{k^i}{a_i} i=1naiki

答案对 p p p 取模。

输入格式

第一行三个正整数 n , p , k n,p,k n,p,k,意义如题目描述。
第二行 n n n 个正整数 a i a_i ai,是你要求逆元的数。

输出格式

输出一行一个整数,表示答案。

样例 #1

样例输入 #1

6 233 42
1 4 2 8 5 7

样例输出 #1

91

提示

对于 30 % 30\% 30% 的数据, 1 ≤ n ≤ 1 0 5 1\le n \le 10^5 1n105

对于 100 % 100\% 100% 数据, 1 ≤ n ≤ 5 × 1 0 6 1\le n \le 5\times 10^6 1n5×106 2 ≤ k < p ≤ 1 0 9 2\le k < p \le 10^9 2k<p109 1 ≤ a i < p 1\le a_i < p 1ai<p,保证 p p p 为质数。

AC题解—快速幂+逆元:

// 线性求任意 n 个数的逆元,这个题目就是他的一个变种
#include <iostream>
using namespace std;
typedef long long ll;
ll n, p, k;
ll qpow(ll a, ll b)
{
    a %= p;
    ll res = 1;
    while (b > 0)
    {
        if (b & 1)
        {
            res = res * a % p;
        }
        a = a * a % p;
        b >>= 1;
    }
    return res;
}
inline int read()
{
    int f = 1, x = 0;
    char ch;
    do
    {
        ch = getchar();
        if (ch == '-')
            f = -1;
    } while (ch < '0' || ch > '9');
    do
    {
        x = x * 10 + ch - '0';
        ch = getchar();
    } while (ch >= '0' && ch <= '9');
    return f * x;
}
int main()
{
    n = read();
    p = read();
    k = read();
    ll ans = 0;
    ll temp = k;
    ll a[n + 5], s[n + 5], sv[n + 5]; // inv[n + 5](可以不存); // a[i]给定的数 s[i]表示i个数的前缀积 sv[i]表示s[i]的逆元  inv[i]表示a[i]的逆元
    for (int i = 1; i <= n; i++)
    {
        a[i] = read();
    }
    s[0] = 1;
    for (int i = 1; i <= n; ++i)
        s[i] = s[i - 1] * a[i] % p; // 求前缀积
    sv[n] = qpow(s[n], p - 2);      // 前缀积的逆元
    for (int i = n; i >= 1; --i)
        sv[i - 1] = sv[i] * a[i] % p;
    // 因为 sv_n 是 n 个数的积的逆元,所以当我们把它乘上 a_n 时,就会和 a_n 的逆元抵消,于是就得到了 a_1 到 a_{n-1} 的积逆元,记为 sv_{n-1}。
    // 同理我们可以依次计算出所有的 sv[i]
    for (int i = 1; i <= n; ++i)
    {
        // inv[i] = sv[i] * s[i - 1] % p;
        // a[i]^(-1)=sv[i]*s[i-1]--->前i个数的逆元*前i-1个数的积
        // ans = (ans + (ll)inv[i] * temp) % p;
        ans = (ans + (ll)(sv[i] * s[i - 1] % p) * temp) % p;
        temp = (temp * k) % p;
    }
    printf("%lld", ans);
    return 0;
}
### 快速幂算法 Python 实现模板 快速幂是一种高效的指数运算方法,能够在 \( O(\log \text{次幂}) \) 的时间内完成大整数的幂运算。以下是基于 Python 的快速幂实现模板: #### 非递归版本 ```python def quick_power(base, exponent, mod): result = 1 base %= mod # 确保base小于mod以减少后续计算量 while exponent != 0: if exponent & 1: # 如果当前指数最低位为1,则累乘结果 result = (result * base) % mod base = (base * base) % mod # 平方基数 exponent >>= 1 # 右移一位相当于除以2 return result ``` 上述代码实现了意义下的快速幂操作[^2]。 --- #### 递归版本 递归形式虽然简洁,但在处理极大数值时可能因栈溢出而失败。 ```python def recursive_quick_power(base, exponent, mod): if exponent == 0: return 1 res = recursive_quick_power(base, exponent >> 1, mod) res = (res * res) % mod if exponent & 1: res = (res * base) % mod return res ``` 此版本通过递归方式逐步缩小问题规并利用平方特性降低复杂度[^3]。 --- #### 使用 NumPy 进行矩阵快速幂 对于涉及矩阵的操作(如斐波那契数列),可以借助 `NumPy` 提升效率: ```python import numpy as np def matrix_multiply(A, B, mod): """矩阵相乘""" return np.mod(np.dot(A, B), mod) def matrix_quick_power(matrix, power, mod): """矩阵快速幂""" result = np.eye(len(matrix), dtype=int) # 单位矩阵初始化 while power > 0: if power & 1: result = matrix_multiply(result, matrix, mod) matrix = matrix_multiply(matrix, matrix, mod) power >>= 1 return result ``` 该函数支持任意大小方形矩阵的快速幂运算,并适用于动态规划中的状态转移优化场景[^4]。 --- #### 应用实例:费马小定理逆元数为质数时,可结合费马小定理高效乘法逆元: \[ a^{-1} \equiv a^{p-2} \ (\bmod\ p) \] 其中 \( p \) 是素数。 ```python MOD = 10**9 + 7 def inverse_fermat(a, p=MOD): return quick_power(a, p - 2, p) ``` 这一技巧广泛应用于组合数学与竞赛编程领域[^5]。 --- ### 总结 以上提供了多种快速幂的 Python 实现方案,包括基础版、递归版以及矩阵扩展版。每种变体均具备特定适用范围和性能特点,在实际开发过程中可根据需灵活选用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值