背景:
多项式全家桶
eating...
\text{eating...}
eating...
题目传送门:
https://www.luogu.org/problemnew/show/P4238
题意:
给定一个多项式
F
(
x
)
F(x)
F(x),求一个多项式
G
(
x
)
G(x)
G(x)使得
F
(
x
)
∗
G
(
x
)
≡
1
(
m
o
d
  
x
n
)
F(x)*G(x)≡1(\mod x^n)
F(x)∗G(x)≡1(modxn)。
思路:
假设我们已经搞定了
F
∗
A
≡
1
(
m
o
d
  
x
⌈
n
2
⌉
)
F*A≡1(\mod x^{\lceil\frac{n}{2}\rceil})
F∗A≡1(modx⌈2n⌉)。
那么有:
F
(
G
−
A
)
≡
0
(
m
o
d
  
x
⌈
n
2
⌉
)
F(G-A)≡0(\mod x^{\lceil\frac{n}{2}\rceil})
F(G−A)≡0(modx⌈2n⌉)
因为
F
≠
0
F≠0
F̸=0,所以有:
G
−
A
≡
0
(
m
o
d
  
x
⌈
n
2
⌉
)
G-A≡0(\mod x^{\lceil\frac{n}{2}\rceil})
G−A≡0(modx⌈2n⌉)
两边同时平方,得:
G
2
+
A
2
−
2
A
G
≡
0
(
m
o
d
  
x
n
)
G^2+A^2-2AG≡0(\mod x^{n})
G2+A2−2AG≡0(modxn)
左右同时乘上
F
F
F,得:
G
+
A
2
F
−
2
A
≡
0
(
m
o
d
  
x
n
)
G
≡
2
A
−
A
2
F
(
m
o
d
  
x
n
)
\begin{aligned}G+A^2F-2A&≡0(\mod x^{n})\\ G&≡2A-A^2F(\mod x^n)\end{aligned}
G+A2F−2AG≡0(modxn)≡2A−A2F(modxn)
用
NTT
\text{NTT}
NTT优化。
最后倍增求解,易证得时间复杂度为:
Θ
(
n
log
n
)
\Theta(n\log n)
Θ(nlogn)。
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
const LL mod=998244353,G=3,inv_G=332748118;
using namespace std;
LL a[300010],b[300010],f[300010],g[300010];
int limit,n,l,r[300010];
LL dg(LL x,LL k)
{
if(!k) return 1;
LL op=dg(x,k>>1);
if(k&1) return op*op%mod*x%mod; else return op*op%mod;
}
LL inv(LL x)
{
return dg(x,mod-2);
}
void NTT(LL *now,int limit,int op)
{
for(int i=0;i<limit;i++)
if(i<r[i]) swap(now[i],now[r[i]]);
for(int mid=1;mid<limit;mid<<=1)
{
LL wn=dg(op==1?G:inv_G,(mod-1)/(mid<<1));
for(int j=0;j<limit;j+=(mid<<1))
{
LL w=1;
for(int k=0;k<mid;k++,w=(w*wn)%mod)
{
LL x=now[j+k],y=w*now[j+k+mid]%mod;
now[j+k]=(x+y)%mod;
now[j+k+mid]=(x-y+mod)%mod;
}
}
}
}
void work(int n,LL *f,LL *g)
{
if(n==1)
{
g[0]=inv(f[0]);
return;
}
work((n+1)>>1,f,g);
limit=1,l=0;
while(limit<(n<<1))
limit<<=1,l++;
for(int i=1;i<limit;i++)
r[i]=((r[i>>1]>>1)|((i&1)<<(l-1)));
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
for(int i=0;i<n;i++)
a[i]=f[i],b[i]=g[i];
NTT(a,limit,1);
NTT(b,limit,1);
for(int i=0;i<limit;i++)
b[i]=b[i]*((2ll-a[i]*b[i]%mod+mod)%mod)%mod;
NTT(b,limit,-1);
LL INV=inv(limit);
for(int i=0;i<n;i++)
g[i]=b[i]*INV%mod;
}
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%lld",&f[i]);
work(n,f,g);
for(int i=0;i<n;i++)
printf("%lld ",g[i]);
}