离线线性求逆元
这里还有一个方法可以在 的时间复杂度内离线求出一个序列每个位置上的数的逆元是多少。这里该序列没有任何限制,可能唯一的限制就是逆元存在。
假设模数为 是一个质数。
考虑设该序列为 ,设其前缀积为 ,设其前缀积的逆元为 ,设该序列的逆元为 ,我们来考虑怎么求。
我们先求出 ,然后用 的时间复杂度内求出 ,我们有以下式子成立:
所以我们仍然可以线性求前缀积的逆元,然而每个位置的逆元满足:
这里我们认为
所以我们就可以在上述复杂度内求出某个序列的逆元来了。
#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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
2021-03-01 代码仓库3——单调栈
2021-03-01 代码仓库2: 对顶堆,对顶栈
2021-03-01 acwing题解——七夕祭
2021-03-01 DS线段树优化最短路&&01bfs浅谈