线性求逆
推导过程(1~n)
\(1^{-1}\equiv 1(\bmod p)\)
设 \(p=k\times i+r,r<i,1<i<p\)。
将这个式子放在 \(\bmod p\) 的意义下,得到 \(k\times i+r\equiv 0(\bmod p)\)。
两边同时乘上 \(i^{-1},r^{-1}\),得到
\(k\times r^{-1}+i^{-1}\equiv 0(\bmod p)\)
\(i^{-1}\equiv-k\times r^{-1}\equiv0(\bmod p)\)
\(i^{-1}\equiv-\lfloor\frac{p}{i}\rfloor\times(p \bmod i)^{-1}(\bmod p)\)
而 \(p \bmod i^{-1}\) 是已经求过的了,因此 \(i^{-1}\) 可以线性求出。
ni[1]=ni[0]=1;
for (int i=2;i<=mx;++i)
ni[i]=(ll)(mod-mod/i)*ni[mod%i]%mod;
推导过程(任意 n个)
求出 \(n\) 个数的前缀积,记作 \(s\)。
用快速幂或者扩展欧几里得求出 \(s_n\) 的逆元,记作 \(sv_n\)。
那么就有 \(sv_i=sv_{i+1}*a_{i+1}\),因为 \(a_{i+1}\) 会和 \(sv_{i+1}\) 中 \(a_{i+1}^{-1}\) 抵消。
求出 \(sv\) 后,\(inv_i=sv_i*s_{i-1}\)。
#include<cstdio>
#define N 5000005
#define mod 1000000007
#define ll long long
using namespace std;
int n;
ll ans,a[N],s[N],sv[N],inv[N];
ll ksm(ll x,ll y)
{
ll res=1;
while (y)
{
if (y&1) res=res*x%mod;
x=x*x%mod;
y>>=1;
}
return res;
}
ll read()
{
ll res=0;int fh=1;char ch=getchar();
while (ch<'0'||ch>'9') {if (ch=='-') fh=-1;ch=getchar();}
while (ch>='0'&&ch<='9') {res=(res<<1)+(res<<3)+(ch-'0');ch=getchar();}
return res*fh;
}
int main()
{
scanf("%d",&n);
s[0]=1;
for (int i=1;i<=n;++i)
a[i]=read(),s[i]=s[i-1]*a[i]%mod;
sv[n]=ksm(s[n],mod-2);
for (int i=n-1;i;--i)
sv[i]=sv[i+1]*a[i+1]%mod;
for (int i=1;i<=n;++i)
inv[i]=sv[i]*s[i-1]%mod;
for (int i=1;i<=n;++i)
ans=(ans+sv[i]*s[i-1]%mod*ksm(1ll*998244353,n-i)%mod)%mod;
printf("%lld\n",ans);
return 0;
}