離線線性求逆元
阿新 • • 發佈:2022-03-01
這裡還有一個方法可以在 \(O(n+\log P)\) 的時間複雜度內離線求出一個序列每個位置上的數的逆元是多少。這裡該序列沒有任何限制,可能唯一的限制就是逆元存在。
假設模數為 \(P\) 是一個質數。
考慮設該序列為 \(a_i\),設其字首積為 \(Pre_i\),設其字首積的逆元為 \(InvPre_i\),設該序列的逆元為 \(Inv_i\),我們來考慮怎麼求。
我們先求出 \(Pre_i\),然後用 \(O(\log P)\) 的時間複雜度內求出 \(InvPre_n\),我們有以下式子成立:
\[ InvPre_n\times a_n\equiv InvPre_{n-1}\times a_n\times a_n^{-1}\equiv InvPre_{n-1}\bmod P \]所以我們仍然可以線性求字首積的逆元,然而每個位置的逆元滿足:
這裡我們認為 \(Pre_0=1\)
所以我們就可以在上述複雜度內求出某個序列的逆元來了。
#include<bits/stdc++.h> #define dd double #define ld long double #define ll long long #define uint unsigned int #define ull unsigned long long #define mset(a,b) memset(a,b,sizeof(a)) #define rep(i,l,r) for(int i=l;i<=r;i++) #define dec(i,l,r) for(int i=r;i>=l;i--) #define fi first #define se second #define mp make_pair #define pb push_back #define N 5000100 #define M number using namespace std; const int INF=0x3f3f3f3f; const int mod=1e9+7; const int base=998244353; template<typename T> inline void read(T &x) { x=0; int f=1; char c=getchar(); for(;!isdigit(c);c=getchar()) if(c == '-') f=-f; for(;isdigit(c);c=getchar()) x=x*10+c-'0'; x*=f; } int n,a[N],Pre[N],InvPre[N],Inv[N]; inline int ksm(int a,int b,int mod){int res=1;while(b){if(b&1)res=1ll*res*a%mod;a=1ll*a*a%mod;b>>=1;}return res;} int main(){ read(n);rep(i,1,n)read(a[i]); Pre[0]=1;rep(i,1,n) Pre[i]=1ll*Pre[i-1]*a[i]%mod; InvPre[n]=ksm(Pre[n],mod-2,mod); dec(i,1,n-1) InvPre[i]=1ll*InvPre[i+1]*a[i+1]%mod; rep(i,1,n) Inv[i]=1ll*InvPre[i]*Pre[i-1]%mod; int now=1,ans=0; dec(i,1,n){ans=(ans+1ll*now*Inv[i]%mod)%mod;now=1ll*now*base%mod;} // rep(i,1,n) printf("%d ",Inv[i]);puts(""); rep(i,1,n){assert(1ll*a[i]*Inv[i]%mod==1);} printf("%d\n",ans); return 0; }