【洛谷P4238】【模板】多项式乘法逆
题目
题目链接:https://www.luogu.com.cn/problem/P4238
给定一个多项式 \(F(x)\) ,请求出一个多项式 \(G(x)\), 满足 \(F(x) * G(x) \equiv 1 ( \mathrm{mod\:} x^n )\)。系数对 \(998244353\) 取模。
\(n\leq 10^5\)。
思路
假设我们已经知道了 \(F(x)G'(x)\equiv 1\pmod {x^{\frac{n}{2}}}\),考虑如何推广到 \(F(x)G(x)\equiv 1\pmod {x^n}\)
首先显然有
\[G(x)-G'(x)\equiv 0\pmod{x^{\frac{n}{2}}}
\]
两边平方后拆开
\[G(x)^2-2G(x)G'(x)+G'(x)^2\equiv 0\pmod{x^{n}}
\]
同时乘上 \(F(x)\)
\[G(x)-2G'(x)+G'(x)^2F(x)\equiv 0\pmod{x^{n}}
\]
所以
\[G(x)\equiv 2G'(x)-G'(x)^2F(x)\pmod{x^{n}}
\]
然后就可以递推了。
\(T(n)=T(\frac{n}{2})+O(n\log n)\),故时间复杂度为 \(O(n\log n)\)。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=300010,MOD=998244353,G=3,Ginv=332748118;
int n,rev[N];
ll f[N],g[2][N],h[N],X[N],Y[N];
ll fpow(ll x,ll k)
{
ll ans=1;
for (;k;k>>=1,x=x*x%MOD)
if (k&1) ans=ans*x%MOD;
return ans;
}
void NTT(ll *f,int tag,int lim)
{
for (int i=0;i<lim;i++)
if (i<rev[i]) swap(f[i],f[rev[i]]);
for (int k=1;k<lim;k<<=1)
{
ll tmp=fpow((tag==1)?G:Ginv,(MOD-1)/(k<<1));
for (int i=0;i<lim;i+=(k<<1))
{
ll w=1;
for (int j=0;j<k;j++,w=w*tmp%MOD)
{
ll x=f[i+j],y=w*f[i+j+k]%MOD;
f[i+j]=(x+y)%MOD; f[i+j+k]=(x-y+MOD)%MOD;
}
}
}
}
void Fmul(ll *f,ll *g,ll lim)
{
memset(X,0,sizeof(X));
memset(Y,0,sizeof(Y));
for (int i=0;i<(lim>>1);i++)
X[i]=f[i],Y[i]=g[i];
NTT(X,1,lim); NTT(Y,1,lim);
for (int i=0;i<lim;i++) X[i]=X[i]*Y[i]%MOD;
NTT(X,-1,lim);
ll inv=fpow(lim,MOD-2);
for (int i=0;i<lim;i++) X[i]=X[i]*inv%MOD;
memcpy(f,X,sizeof(X));
}
void Finv(ll *f)
{
g[0][0]=fpow(f[0],MOD-2);
int id=0;
for (int lim=4;lim<(n<<2);lim<<=1)
{
id^=1;
for (int i=0;i<lim;i++)
rev[i]=(rev[i>>1]>>1)|((i&1)?(lim>>1):0);
memcpy(h,g[id^1],sizeof(h));
Fmul(h,g[id^1],lim); Fmul(h,f,lim);
for (int i=0;i<(lim>>1);i++)
g[id][i]=(2*g[id^1][i]-h[i]+MOD)%MOD;
}
for (int i=0;i<n;i++)
printf("%lld ",g[id][i]);
}
int main()
{
scanf("%d",&n);
for (int i=0;i<n;i++)
scanf("%lld",&f[i]);
Finv(f);
return 0;
}