线性求逆元
线性求逆元
算法功能
在 \(O(n)\) 的时间内求出某一序列各个数的逆元
算法流程
- 首先, 预处理出序列
a[i]
的前缀积s[i]
- 然后通过快速幂单点求出
s[n]
的逆元 - 倒序循环, 通过倒序乘原序列中的数, 求得
s[i]
的逆元 - 最后我们所需要的单点逆元, 就是
s[i]
的逆元与s[i-1]
的积
代码
/*************************************************************************
> File Name: p5431.cpp
> Author: Typedef
> Mail: 1815979752@qq.com
> Created Time: 2021年07月09日 星期五 07时32分57秒
> Tags:
************************************************************************/
#include<bits/stdc++.h>
using namespace std;
const int N=5e6+7;
typedef long long ll;
ll n,p,k,K,ans=0;
ll a[N],inv[N];
ll s[N];
template<class T>void qread(T &x){
x=0;bool f=0;char c=getchar();
while(c<'0'||c>'9'){if(c=='-') f=1;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c^48);c=getchar();}
if(f) x=-x;
}
ll qpow(ll a,ll b){
ll res=1;
while(b){
if(b&1) res=(res*a)%p;
a=(a*a)%p;
b>>=1;
}
return res;
}
int main(){
inv[n+1]=s[0]=1;
qread(n),qread(p),qread(k);
for(int i=1;i<=n;i++) qread(a[i]),s[i]=(s[i-1]*a[i])%p;
inv[n+1]=qpow(s[n],p-2),K=k;
for(int i=n;i;i--) inv[i]=(inv[i+1]*a[i])%p;
for(int i=1;i<=n;i++){
ans=(ans+(K*(inv[i+1]*s[i-1]%p)%p)%p)%p;
K=(K*k)%p;
}
printf("%lld\n",ans);
return 0;
}