乘法逆元

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

由于输出太多不好,所以将会给定常数 \(k\),你要输出的答案为:

\[\sum\limits_{i=1}^n\frac{k^i}{a_i} \]

答案对 \(p\) 取模。

逆元

已知求逆元的方法有快速幂\(a^{-1} = power(a,p - 2,p)\)
线性递推求逆元

inv[1] = 1;
for (int i = 2; i <= n; ++i) {
  inv[i] = (long long)(p - p / i) * inv[p % i] % p;
}

经过观察发现本题数并不是连续的因此我们不能用这种方法
\(S_n\)\(a_n\)的前缀积\(( a_1 \times a_2 \times a_3 \dots a_n)\)
求得$S_n $的逆元称作 \(Sv_n\)
因为\(Sv_n\)\(a_n\)的积逆元,由逆元互逆运算法则\(Sv_n \times a_n = Sv_{n-1}\)

\[a^{-1}_i = S_{i - 1} \times Sv_i \]

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 5e6 + 10;
ll a[N];
ll s[N],sv[N];
ll n,p,k,ans;

ll read()
{
    ll x = 0, f = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9')
    {
        if (ch == '-')
        {
            f = -1;
        }
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9')
    {
        x = x * 10 + ch - '0';
        ch = getchar()

            ;
    }
    return x * f;
}

ll power(int a,int b)
{
    ll res = 1;
    while(b)
    {
        if(b&1)res = (ll)res * a % p;
        a = (ll)a * a % p;
        b >>= 1;
    }
    return  res;
}

int main()
{

    n = read();
    p = read();
    k = read();
    s[0] = 1;
    for(int i = 1 ; i <= n ; i ++ )
    {        
        a[i] = read();
        s[i] = (a[i] * s[i - 1]) % p;
    }
    sv[n + 1] = power(s[n],p-2);
    for(int i = n; i >= 1 ; i --)
    {
        sv[i] = (sv[i + 1] * a[i]) % p;
    }

    ll tmp = k;

    for(int i = 1 ; i <= n ; i ++ )
    {
        ans =(ans + ((sv[i + 1] * s[i - 1]) % p ) * tmp) % p;
        tmp = (tmp * k )% p;
    }
    cout << ans << "\n";


}
posted @ 2022-07-17 17:31  Erfu  阅读(40)  评论(0编辑  收藏  举报