题目
题目链接:https://www.luogu.com.cn/problem/P4238
给定一个多项式 (F(x)) ,请求出一个多项式 (G(x)), 满足 (F(x) * G(x) equiv 1 ( mathrm{mod:} x^n ))。系数对 (998244353) 取模。
(nleq 10^5)。
思路
假设我们已经知道了 (F(x)G'(x)equiv 1pmod {x^{frac{n}{2}}}),考虑如何推广到 (F(x)G(x)equiv 1pmod {x^n})
首先显然有
[G(x)-G'(x)equiv 0pmod{x^{frac{n}{2}}}
]
两边平方后拆开
[G(x)^2-2G(x)G'(x)+G'(x)^2equiv 0pmod{x^{n}}
]
同时乘上 (F(x))
[G(x)-2G'(x)+G'(x)^2F(x)equiv 0pmod{x^{n}}
]
所以
[G(x)equiv 2G'(x)-G'(x)^2F(x)pmod{x^{n}}
]
然后就可以递推了。
(T(n)=T(frac{n}{2})+O(nlog n)),故时间复杂度为 (O(nlog 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;
}