原题链接
题目大意
给定一个多项式 F ( x ) F(x) F(x),请求出一个多项式 G ( x ) G(x) G(x),满足 F ( x ) ⋅ G ( x ) ≡ 1 ( m o d x n ) F(x)\cdot G(x)\equiv 1\pmod{x^n} F(x)⋅G(x)≡1(modxn)。系数对 998244353 998244353 998244353 取模。
输入格式
第一行一个整数
n
n
n。
接下来一行
n
n
n 个数字,从低到高表示
F
(
x
)
F(x)
F(x) 的系数。
输出格式
一行 n n n 个数字,从低到高表示 G ( x ) G(x) G(x) 的系数,保证有解。
S a m p l e \mathbf{Sample} Sample I n p u t \mathbf{Input} Input
5
1 6 3 4 9
S a m p l e \mathbf{Sample} Sample O u t p u t \mathbf{Output} Output
1 998244347 33 998244169 1020
H
i
n
t
&
E
x
p
l
a
i
n
\mathbf{Hint\&Explain}
Hint&Explain
图像画不出来。(实际上不想做)
数据范围
对于 100 % 100\% 100% 的数据, 1 ≤ n ≤ 1 0 5 , 0 ≤ a i ≤ 1 0 9 1 \le n\le 10^5,0\le a_i \le 10^9 1≤n≤105,0≤ai≤109。
解题思路
在介绍本题之前,你需要知道一些前置的知识。
前置知识
1.NTT
\texttt{1.NTT}
1.NTT
不会NTT的同学可以看我写的关于NTT的详解。
Click
me!
\texttt{Click me!}
Click me!
正文部分
首先,我们知道
F
(
x
)
⋅
G
(
x
)
≡
1
(
m
o
d
x
n
)
F(x)\cdot G(x)\equiv 1\pmod{x^n}
F(x)⋅G(x)≡1(modxn)
假设我们现在已经求出了
F
(
x
)
F(x)
F(x) 在模
x
⌈
n
2
⌉
x^{\left\lceil\frac n2\right\rceil}
x⌈2n⌉ 下的逆元
B
B
B,则有
F
(
x
)
⋅
B
(
x
)
≡
1
(
m
o
d
x
⌈
n
2
⌉
)
F(x)\cdot B(x)\equiv 1\pmod{x^{\left\lceil\frac n2\right\rceil}}
F(x)⋅B(x)≡1(modx⌈2n⌉)
两式相减,再同时除以
F
(
x
)
F(x)
F(x),得
G
(
x
)
−
B
(
x
)
≡
0
(
m
o
d
x
⌈
n
2
⌉
)
G(x)-B(x)\equiv0\pmod{x^{\left\lceil\frac n2\right\rceil}}
G(x)−B(x)≡0(modx⌈2n⌉)
平方,得
G
(
x
)
2
−
2
G
(
x
)
B
(
x
)
+
B
(
x
)
2
≡
0
(
m
o
d
x
n
)
G(x)^2-2G(x)B(x)+B(x)^2\equiv0\pmod{x^n}
G(x)2−2G(x)B(x)+B(x)2≡0(modxn)
乘上
F
(
x
)
F(x)
F(x),得
G
(
x
)
−
2
B
(
x
)
+
F
(
x
)
B
(
x
)
2
≡
0
(
m
o
d
x
n
)
G(x)-2B(x)+F(x)B(x)^2\equiv0\pmod{x^n}
G(x)−2B(x)+F(x)B(x)2≡0(modxn)
移项,得
G
(
x
)
=
2
B
(
x
)
−
F
(
x
)
B
(
x
)
2
(
m
o
d
x
n
)
G(x)=2B(x)-F(x)B(x)^2\pmod{x^n}
G(x)=2B(x)−F(x)B(x)2(modxn)
把
B
(
x
)
B(x)
B(x)提取出来,得到
G
(
x
)
=
(
2
−
F
(
x
)
⋅
B
(
x
)
)
⋅
B
(
x
)
(
m
o
d
x
n
)
G(x)=(2-F(x)\cdot B(x))\cdot B(x)\pmod{x^n}
G(x)=(2−F(x)⋅B(x))⋅B(x)(modxn)
直接从小到大递归用多项式乘法套公式即可。
上代码
#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
#define int ll
typedef long long ll;
namespace Polynomial{
// The value of the variable below can be changed.
const int max_size_of_array=400000;
// The value of the variable above can be changed.
const int maxSize=max_size_of_array+10;
const int g=3,invg=332748118;
const int p=998244353;
int resort[maxSize];
int inv1[maxSize];
int lim,dig;
void print_elem(string name,int *f,int len)
{
cout<<name<<":";
for(int i=0; i<len; i++)
cout<<f[i]<<" ";
cout<<endl;
return;
}
int power(int a,int b,int p)
{
int tar=1;
for(; b; b>>=1,a=(1ll*a*a)%p)
if(b&1)
tar=(1ll*tar*a)%p;
return tar%p;
}
void NTT(int *c,int lim,int state)
{
// cout<<"NTT"<<endl;
for(int i=0; i<lim; i++)
if(i<resort[i])
swap(c[i],c[resort[i]]);
for(int i=1; i<lim; i<<=1)
{
int W1n=power(g,1ll*(p-1)/(i<<1),p);
for(int Size=i<<1,j=0; j<lim; j+=Size)
{
int W=1;
for(int k=0; k<i; k++,W=(1ll*W*W1n)%p)
{
int x=(1ll*c[j+k]+p)%p,y=(1ll*W*c[j+i+k]+p)%p;
c[j+k]=(1ll*x+y+p)%p;
c[j+i+k]=(1ll*x-y+p)%p;
// if(j+k==0)
// cout<<"\t"<<c[j+k]<<"\tNTT"<<endl;
}
}
}
if(state==1)
return;
int temp=power(lim,p-2,p);
reverse(c+1,c+lim);
for(int i=0; i<lim; i++)
c[i]=1ll*c[i]*temp%p;
return;
}
void getInv(int *f,int *g,int size)
{
// cout<<"getInv "<<size<<" "<<((size+1)>>1)<<endl;
// getInv(f,g,size);
if(size==1)
{
g[0]=power(f[0],p-2,p);
// print_elem("\t",g,size);
return;
}
// print_elem("\t",g,size);
getInv(f,g,(size+1)>>1);
// print_elem("\t",g,size);
lim=1,dig=0;
while(lim<(size<<1))
lim<<=1,dig++;
for(int i=1; i<lim; i++)
resort[i]=(resort[i>>1]>>1)|((i&1)<<(dig-1));
for(int i=0; i<size; i++)
inv1[i]=f[i];
for(int i=size; i<lim; i++)
inv1[i]=0;
NTT(inv1,lim,1);
NTT(g,lim,1);
for(int i=0; i<lim; i++)
g[i]=1ll*((2ll-inv1[i]*g[i]%p+p)%p*g[i]%p+p)%p;
NTT(g,lim,-1);
for(int i=size; i<lim; i++)
g[i]=0;
// print_elem("\t",g,size);
return;
}
}
using namespace Polynomial;
int a[maxSize];
int b[maxSize];
int n;
signed main()
{
// ios::sync_with_stdio(false);
cin.tie(0);
/* Code */
cin>>n;
for(int i=0; i<n; i++)
cin>>a[i];
getInv(a,b,n);
for(int i=0; i<n; i++)
cout<<b[i]<<" ";
cout<<endl;
return 0;
}
完美切题 ∼ \sim ∼