题意:
给定一个
n
n
n次多项式
F
(
x
)
F(x)
F(x)和一个
m
m
m次多项式
G
(
x
)
G(x)
G(x),请求出多项式
Q
(
x
)
Q(x)
Q(x),
R
(
x
)
R(x)
R(x),满足以下条件:
Q
(
x
)
Q(x)
Q(x)次数为
n
−
m
n-m
n−m,
R
(
x
)
R(x)
R(x)次数小于
m
m
m,
F
(
x
)
=
Q
(
x
)
∗
G
(
x
)
+
R
(
x
)
F(x) = Q(x) * G(x) + R(x)
F(x)=Q(x)∗G(x)+R(x)。所有的运算在模
998244353
998244353
998244353意义下进行。
n
<
=
100000
n<=100000
n<=100000
题解:
我们来介绍一下多项式除法。前置知识:多项式求逆、NTT。
我们定义一个
A
R
(
x
)
=
x
n
A
(
1
x
)
A^R(x)=x^nA(\frac{1}{x})
AR(x)=xnA(x1),我们把右边展开,可以发现其实与
A
(
x
)
A(x)
A(x)的区别就是原来
x
,
x
2
,
x
3
.
.
.
x
n
x,x^2,x^3...x^n
x,x2,x3...xn的系数分别是
a
1
,
a
2
,
a
3
.
.
.
a
n
a_1,a_2,a_3...a_n
a1,a2,a3...an,现在变成了
a
n
,
a
n
−
1
.
.
.
a
1
a_n,a_{n-1}...a_1
an,an−1...a1,也就是翻转了系数。
我们本来有
F
(
x
)
=
Q
(
x
)
∗
G
(
x
)
+
R
(
x
)
F(x) = Q(x) * G(x) + R(x)
F(x)=Q(x)∗G(x)+R(x) 现在等式两边同时乘
x
n
x^n
xn,并且把每个函数尽可能构造成用
A
R
A^R
AR型的函数来表示,我们可以得到:
x
n
∗
F
(
x
)
=
x
n
−
m
∗
Q
(
x
)
∗
x
m
∗
G
(
x
)
+
x
n
−
m
+
1
∗
x
m
−
1
R
(
x
)
x^n*F(x) = x^{n-m}*Q(x) * x^m*G(x) + x^{n-m+1}*x^{m-1}R(x)
xn∗F(x)=xn−m∗Q(x)∗xm∗G(x)+xn−m+1∗xm−1R(x)
F
R
(
x
)
=
Q
R
(
x
)
∗
G
R
(
x
)
+
x
n
−
m
+
1
R
R
F^R(x)=Q^R(x)*G^R(x)+x^{n-m+1}R^R
FR(x)=QR(x)∗GR(x)+xn−m+1RR我们等式两边同时模一个
x
n
−
m
+
1
x^{n-m+1}
xn−m+1,就可以把
x
n
−
m
+
1
∗
x
m
−
1
R
(
x
)
x^{n-m+1}*x^{m-1}R(x)
xn−m+1∗xm−1R(x)消掉,同时不会影响到
x
n
−
m
∗
Q
(
x
)
x^{n-m}*Q(x)
xn−m∗Q(x),因为这个多项式的最高次数只有
n
−
m
n-m
n−m。这样就变成了
F
R
(
x
)
≡
Q
R
(
x
)
∗
G
R
(
x
)
(
m
o
d
x
n
−
m
+
1
)
F^R(x)\equiv Q^R(x)*G^R(x)(mod\ x^{n-m+1})
FR(x)≡QR(x)∗GR(x)(mod xn−m+1) 我们已知了
F
(
x
)
F(x)
F(x)和
G
(
x
)
G(x)
G(x)的各项系数,那么只要系数翻转一下就可以得到对应的
F
R
(
x
)
F^R(x)
FR(x)和
G
R
(
x
)
G^R(x)
GR(x)的各项系数,我们要求
Q
(
x
)
Q(x)
Q(x)的系数,可以先求出
Q
R
(
x
)
Q^R(x)
QR(x)的系数,再翻转回来就好了。所以我们把式子变成
Q
R
(
x
)
≡
F
R
(
x
)
∗
G
−
R
(
x
)
(
m
o
d
x
n
−
m
+
1
)
Q^R(x)\equiv F^R(x)*G^{-R}(x)(mod\ x^{n-m+1})
QR(x)≡FR(x)∗G−R(x)(mod xn−m+1) 我们发现对于
G
−
R
G^{-R}
G−R,我们需要对
G
R
(
x
)
G^R(x)
GR(x)进行一次多项式求逆。然后求出
Q
(
x
)
Q(x)
Q(x)之后我们再用
R
(
x
)
=
F
(
x
)
−
Q
(
x
)
∗
G
(
x
)
R(x)=F(x)-Q(x)*G(x)
R(x)=F(x)−Q(x)∗G(x)算出
R
(
x
)
R(x)
R(x)的各项系数即可。
有了多项式除法之后我们还可以做一些多项式取模、多项式gcd之类的东西。
代码:
#include <bits/stdc++.h>
using namespace std;
int n,m,l,rev[500010];
long long a[500010],b[500010],aa[500010],bb[500010],c[500010];
const long long mod=998244353,g=3,gi=332748118;
inline int read()
{
int x=0;
char s=getchar();
while(s>'9'||s<'0')
s=getchar();
while(s>='0'&&s<='9')
{
x=x*10+s-'0';
s=getchar();
}
return x;
}
inline long long ksm(long long x,long long y)
{
long long res=1;
while(y)
{
if(y&1)
res=res*x%mod;
x=x*x%mod;
y>>=1;
}
return res;
}
inline void ntt(long long *a,int dft,int len)
{
l=0;
int ji=len;
for(len=1;len<ji;len<<=1)
++l;
for(int i=0;i<len;++i)
rev[i]=(rev[i>>1]>>1)|((i&1)<<(l-1));
for(int i=0;i<len;++i)
{
if(i<rev[i])
swap(a[i],a[rev[i]]);
}
for(int i=1;i<len;i<<=1)
{
long long wn=ksm((dft==1?g:gi),(mod-1)/(i<<1));
for(int j=0,p=(i<<1);j<len;j+=p)
{
long long w=1;
for(int k=0;k<i;++k)
{
long long x=a[j+k],y=w*a[i+j+k]%mod;
a[j+k]=(x+y)%mod;
a[i+j+k]=(x-y+mod)%mod;
w=w*wn%mod;
}
}
}
if(dft==-1)
{
int ni=ksm(ji,mod-2);
for(int i=0;i<len;++i)
a[i]=a[i]*ni%mod;
}
}
inline void inv(long long *a,long long *b,int len)
{
if(len==1)
{
b[0]=ksm(a[0],mod-2);
return;
}
inv(a,b,len>>1);
for(int i=0;i<len;++i)
{
aa[i]=a[i];
bb[i]=b[i];
}
ntt(aa,1,len<<1);
ntt(bb,1,len<<1);
for(int i=0;i<(len<<1);++i)
aa[i]=aa[i]*bb[i]%mod*bb[i]%mod;
ntt(aa,-1,len<<1);
for(int i=0;i<len;++i)
b[i]=(b[i]*2%mod-aa[i]+mod)%mod;
for(int i=0;i<(len<<1);++i)
{
aa[i]=0;
bb[i]=0;
}
}
int main()
{
n=read();
m=read();
for(int i=0;i<=n;++i)
a[i]=read();
for(int i=0;i<=m;++i)
b[i]=read();
reverse(a,a+n+1);
reverse(b,b+m+1);
for(l=1;l<=n-m;l<<=1);
inv(b,c,l);
int ji;
for(ji=1;ji<=(n-m);ji<<=1);
ji<<=1;
for(int i=0;i<=n-m;++i)
aa[i]=a[i];
ntt(aa,1,ji);
ntt(c,1,ji);
for(int i=0;i<=ji;++i)
c[i]=c[i]*aa[i]%mod;
ntt(c,-1,ji);
reverse(c,c+n-m+1);
for(int i=n-m+1;i<=2*n;++i)
c[i]=0;
for(int i=0;i<=n-m;++i)
printf("%lld ",c[i]);
printf("\n");
reverse(a,a+n+1);
reverse(b,b+m+1);
for(ji=1;ji<=max(n-m,m);ji<<=1);
ji<<=1;
ntt(c,1,ji);
ntt(b,1,ji);
for(int i=0;i<=ji;++i)
b[i]=1ll*c[i]*b[i]%mod;
ntt(b,-1,ji);
for(int i=0;i<m;++i)
printf("%lld ",(a[i]-b[i]+mod)%mod);
return 0;
}