多项式算法7:多项式除法
多项式除法
算法简述:
给定多项式 F F F , G G G求出多项式 R R R, Q Q Q使得 F = G × Q + R F=G \times Q + R F=G×Q+R。
其中 F F F的次数为 n n n, G G G的次数为 m m m,一般 n > m n \gt m n>m。
首先,我们列出式子:
F
(
x
)
=
G
(
x
)
×
Q
(
x
)
+
R
(
x
)
F(x)=G(x) \times Q(x) + R(x)
F(x)=G(x)×Q(x)+R(x)我们把
x
x
x换成
1
x
\frac{1}{x}
x1得:
F
(
1
x
)
=
G
(
1
x
)
×
Q
(
1
x
)
+
R
(
1
x
)
F(\frac{1}{x})=G(\frac{1}{x}) \times Q(\frac{1}{x}) + R(\frac{1}{x})
F(x1)=G(x1)×Q(x1)+R(x1)两边乘以
x
n
x^n
xn可得:
F
(
1
x
)
x
n
=
G
(
1
x
)
x
m
×
Q
(
1
x
)
x
n
−
m
+
R
(
1
x
)
x
n
F(\frac{1}{x}) x^{n}=G(\frac{1}{x}) x^{m} \times Q(\frac{1}{x}) x^{n-m} + R(\frac{1}{x})x^{n}
F(x1)xn=G(x1)xm×Q(x1)xn−m+R(x1)xn
F
(
1
x
)
x
n
=
G
(
1
x
)
x
m
×
Q
(
1
x
)
x
n
−
m
+
R
(
1
x
)
x
m
−
1
×
x
n
−
m
+
1
F(\frac{1}{x}) x^{n}=G(\frac{1}{x}) x^{m} \times Q(\frac{1}{x}) x^{n-m} + R(\frac{1}{x}) x^{m-1} \times x^{n-m+1}
F(x1)xn=G(x1)xm×Q(x1)xn−m+R(x1)xm−1×xn−m+1我们设
A
r
(
x
)
=
x
n
A
(
1
x
)
A_r(x)=x^nA(\frac{1}{x})
Ar(x)=xnA(x1),不难发现,两个多项式满足
A
r
(
x
)
A_r(x)
Ar(x)的第
i
i
i项系数等于
A
(
x
)
A(x)
A(x)的第
n
−
i
n-i
n−i项系数。把
A
(
x
)
A(x)
A(x)翻转一下就可以得到
A
r
(
x
)
A_r(x)
Ar(x)。
故我们根据上面的式子可得:
F
r
(
x
)
=
G
r
(
x
)
×
Q
r
(
x
)
+
R
r
(
x
)
x
n
−
m
+
1
F_r(x)=G_r(x) \times Q_r(x) + R_r(x)x^{n-m+1}
Fr(x)=Gr(x)×Qr(x)+Rr(x)xn−m+1
F
r
(
x
)
≡
G
r
(
x
)
×
Q
r
(
x
)
+
R
r
(
x
)
x
n
−
m
+
1
(
m
o
d
x
n
−
m
+
1
)
F_r(x) \equiv G_r(x) \times Q_r(x) + R_r(x)x^{n-m+1} (\mod x^{n-m+1} )
Fr(x)≡Gr(x)×Qr(x)+Rr(x)xn−m+1(modxn−m+1)
F
r
(
x
)
≡
G
r
(
x
)
×
Q
r
(
x
)
(
m
o
d
x
n
−
m
+
1
)
F_r(x) \equiv G_r(x) \times Q_r(x) (\mod x^{n-m+1} )
Fr(x)≡Gr(x)×Qr(x)(modxn−m+1)
Q
r
(
x
)
≡
F
r
(
x
)
×
G
r
−
1
(
x
)
(
m
o
d
x
n
−
m
+
1
)
Q_r(x) \equiv F_r(x) \times G_r^{-1}(x) (\mod x^{n-m+1} )
Qr(x)≡Fr(x)×Gr−1(x)(modxn−m+1)求
G
r
(
x
)
G_r(x)
Gr(x)的逆,然后就可以利用多项式乘法求出
Q
r
(
x
)
Q_r(x)
Qr(x)和
Q
(
x
)
Q(x)
Q(x),然后再
R
(
x
)
=
F
(
x
)
−
G
(
x
)
×
Q
(
x
)
R(x)=F(x)-G(x) \times Q(x)
R(x)=F(x)−G(x)×Q(x)直接计算即可,时间复杂度
Θ
(
n
log
n
)
\varTheta(n \log n)
Θ(nlogn)。
模板题
F
r
(
x
)
×
G
r
−
1
(
x
)
F_r(x) \times G_r^{-1}(x)
Fr(x)×Gr−1(x)的运算要记得先把
n
−
m
+
1
n-m+1
n−m+1以及后面的项清零,否则不知为何会WA,这是我调了5个小时得到的教训 。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#define ll long long
using namespace std;
const int N = 1 << 22;
const int g = 3 , gi = 332748118 , mod = 998244353;
ll qw( ll a , ll b ) {
ll ans = 1;
while ( b ) {
if( b & 1 ) {
ans = ans * a % mod;
}
a = a * a % mod;
b >>= 1;
}
return ans;
}
int rev[N];
int n , m;
void pre( int bit ) {
for ( int i = 0 ; i < ( 1 << bit ) ; ++i ) {
rev[i] = (rev[i>>1]>>1)|((i&1)<<(bit - 1));
}
}
void NTT( ll *F , int len , int on ) {
for ( int i = 0 ; i < len ; ++i ) {
if ( i < rev[i] ) {
swap( F[i] , F[rev[i]] );
}
}
for ( int i = 2 ; i <= len ; i <<= 1 ) {
ll gn = qw( on ? g : gi , ( mod - 1 ) / ( i ) );
for ( int j = 0 ; j <= len - 1 ; j += i ) {
ll gg = 1;
for ( int k = j ; k < j + i / 2 ; ++k ) {
ll u = F[k];
ll v = gg * F[k + i / 2] % mod;
F[k] = (u + v) % mod;
F[k + i / 2] = ( u - v + mod ) % mod;
gg = gg * gn % mod;
}
}
}
return;
}
void mul( ll *a , ll *b , int bit ) {
pre( bit );
int len = ( 1 << bit );
NTT( a , len , 1 );
NTT( b , len , 1 );
for ( int i = 0 ; i < len ; ++i ) {
a[i] = a[i] * b[i] % mod;
}
NTT( a , len , 0 );
ll inv = qw( (ll)len , mod - 2 );
for ( int i = 0 ; i < len ; ++i ) {
a[i] = a[i] * inv % mod;
}
}
ll ta[N] , tb[N];
void getinv( int len , ll *a , ll *b ) {
if( len == 1 ) {
b[0] = qw( a[0] , mod - 2 );
return;
}
getinv( ( len + 1 ) >> 1 , a , b );
int l = 1;
int bit = 0;
while ( l <= len + m ) {
l <<= 1;
++bit;
}
pre( bit );
for ( int i = 0 ; i < l ; ++i ) {
ta[i] = a[i];
tb[i] = ( i < ( ( len + 1 ) >> 1 ) ? b[i] : 0 );
}
NTT( ta , l , 1 );
NTT( tb , l , 1 );
for ( int i = 0 ; i < l ; ++i ) {
ta[i] = tb[i] * ( ( ( 2 - ta[i] * tb[i] ) % mod + mod ) % mod ) % mod;
}
NTT( ta , l , 0 );
ll inv = qw( l , mod - 2 );
for ( int i = 0 ; i < len ; ++i ) {
b[i] = ta[i] * inv % mod;
}
}
ll ff[N] , gg[N] , ffr[N] , ggr[N] , invg[N] , q[N] , r[N] , tem[N];
int main(){
scanf("%d%d",&n,&m);
for ( int i = 0 ; i <= n ; ++i ) {
scanf("%lld",&ff[i]);
}
for ( int i = 0 ; i <= n ; ++i ) {
ffr[i] = ff[n - i];
}
for ( int i = 0 ; i <= m ; ++i ) {
scanf("%lld",&gg[i]);
}
for ( int i = 0 ; i <= m ; ++i ) {
ggr[i] = gg[m - i];
}
for ( int i = n - m + 2 ; i <= m ; ++i ) {
ggr[i] = 0;
ffr[i] = 0;
}
int bit = 0;
int len = 1;
while ( len <= 2 * ( n - m + 1 ) ) {
len <<= 1;
++bit;
}
getinv( len , ggr , invg );
for ( int i = n - m + 1 ; i < N ; ++i ) {
invg[i] = 0;//取模,把后面的清零,不然会WA
}
for ( int i = n - m + 1 ; i < N ; ++i ) {
ffr[i] = 0;//取模,把后面的清零,不然会WA
}
mul( ffr , invg , bit );
for ( int i = 0 ; i <= n - m ; ++i ) {
q[n - m - i] = ffr[i];
}
for ( int i = 0 ; i <= n - m ; ++i ) {
printf("%lld ",q[i]);
}
puts("");
bit = 0;
len = 1;
while ( len <= n + 2 ) {
len <<= 1;
++bit;
}
mul( gg , q , bit );
for ( int i = 0 ; i <= m - 1 ; ++i ) {
r[i] = ( ( ff[i] - gg[i] ) % mod + mod ) % mod;
printf("%lld ",r[i]);
}
return 0;
}