题解 【洛谷 P5431 【模板】乘法逆元2】

\(\large\mathcal{Decription}\)

给定 \(n,p,k\) 及数列 \(a_i\). 求:

\[(\sum\limits_{i=1}^n \dfrac{k^i}{a_i}) \bmod p \]

\(1\le n\le 5\times 10 ^ 6, 2\le k < p \le 10^9, 1\le a_i < p.\)

\(\large\mathcal{Solution}\)

题目即要求 \(a_1, a_2, \cdots a_n\)\(p\) 的逆元。算是一个 \(\text{trick}\) 吧,下面给出 \(\mathcal{O}(n)\) 离线求逆元的算法。

\(\Pi(i)\) 表示 \(a_1a_2...a_i\bmod p\), 容易将其 \(\mathcal{O}(n)\) 处理出来。

\(Inv(i)\) 表示 \(\Pi(i)\)\(p\) 的逆元,我们容易得到公式:

\[Inv(i) = Inv(i + 1)\times a_{i+1}\bmod p \]

那么就能 \(\mathcal{O}(n)\) 处理出 \(Inv(i).\)

\(inv(i)\) 表示 \(a_i\)\(p\) 的逆元,那么有:

\[inv(i) = Inv(i)\times \Pi(i-1)\bmod p \]

那么就能 \(\mathcal{O}(n)\) 处理出 \(inv(i).\) 至此,问题得解。

\(\large\mathcal{Code}\)

#include <bits/stdc++.h>
#define reg register

using namespace std;

const int N = 5000010;

int n, p, k, a[N];
int pi[N], inv_pi[N], inv[N]; // inv_pi 即 Inv 数组

inline int read()
{
    reg int x = 0;
    reg char ch = getchar();
    while (ch < '0' || ch > '9') ch = getchar();
    while ('0' <= ch && ch <= '9')
    {
        x = (x << 1) + (x << 3) + (ch ^ 48);
        ch = getchar();
    }
    return x;
}

inline int qpow(reg int a, reg int b, reg int p)
{
    reg int res = 1;
    for (; b; b >>= 1)
    {
        if (b % 2 == 1) res = 1ll * res * a % p;
        a = 1ll * a * a % p; 
    }
    return res;
}

int main()
{
    n = read(); p = read(); k = read();
    for (reg int i = 1; i <= n; ++ i) a[i] = read();
    
    pi[1] = a[1];
    for (reg int i = 2; i <= n; ++ i) pi[i] = 1ll * pi[i - 1] * a[i] % p;
    
    inv_pi[n] = qpow(pi[n], p - 2, p);
    for (reg int i = n - 1; i >= 1; -- i) inv_pi[i] = 1ll * inv_pi[i + 1] * a[i + 1] % p;
    
    inv[1] = inv_pi[1];
    for (reg int i = 2; i <= n; ++ i) inv[i] = 1ll * pi[i - 1] * inv_pi[i] % p;
    
    reg int ans = 0;
    for (reg int i = n; i >= 1; -- i) ans = 1ll * (ans + inv[i]) * k % p;
    
    printf("%d\n", ans);
    
    return 0;
}
posted @ 2021-08-11 19:57  DreamsChaser  阅读(84)  评论(1)    收藏  举报
Live2D