1. 程式人生 > 其它 >線性求逆元

線性求逆元

線性求逆元

傳送錨點

演算法功能

\(O(n)\) 的時間內求出某一序列各個數的逆元

演算法流程

  • 首先, 預處理出序列 a[i] 的字首積 s[i]
  • 然後通過快速冪單點求出 s[n] 的逆元
  • 倒序迴圈, 通過倒序乘原序列中的數, 求得 s[i] 的逆元
  • 最後我們所需要的單點逆元, 就是 s[i] 的逆元與 s[i-1] 的積

程式碼

/*************************************************************************
    > File Name: p5431.cpp
    > Author: Typedef 
    > Mail: [email protected] 
    > 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;
}