洛谷传送门
题目描述
给定一个 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
n
n,
m
m
m,意义如上。
第二行
n
+
1
n+1
n+1 个整数,从低到高表示
F
(
x
)
F(x)
F(x) 的各个系数。
第三行
m
+
1
m+1
m+1 个整数,从低到高表示
G
(
x
)
G(x)
G(x) 的各个系数。
输出格式:
第一行
n
−
m
+
1
n-m+1
n−m+1 个整数,从低到高表示
Q
(
x
)
Q(x)
Q(x) 的各个系数。
第二行
m
m
m 个整数,从低到高表示
R
(
x
)
R(x)
R(x) 的各个系数。
如果
R
(
x
)
R(x)
R(x) 不足
m
−
1
m-1
m−1 次,多余的项系数补
0
0
0。
输入输出样例
输入样例#1:
5 1
1 9 2 6 0 8
1 7
输出样例#1:
237340659 335104102 649004347 448191342 855638018
760903695
说明
对于所有数据, 1 ≤ m < n ≤ 1 0 5 1 \le m < n \le 10^5 1≤m<n≤105,给出的系数均属于 [ 0 , 998244353 ) ∩ Z [0, 998244353) \cap \mathbb{Z} [0,998244353)∩Z。
解题分析
设 F R ( x ) = x n F ( 1 x ) F_R(x)=x^nF(\frac{1}{x}) FR(x)=xnF(x1), 可以发现 F R ( x ) F_R(x) FR(x)和 F ( x ) F(x) F(x)的系数正好从大到小正好相反。
那么就有:
F
(
1
x
)
=
Q
(
1
x
)
G
(
1
x
)
+
R
(
1
x
)
F
R
(
x
)
=
Q
R
(
x
)
G
R
(
x
)
+
x
n
−
m
+
1
R
R
(
x
)
F
R
(
x
)
≡
Q
R
(
x
)
G
R
(
x
)
(
m
o
d
x
n
−
m
+
1
)
Q
R
(
x
)
≡
F
R
(
x
)
G
R
(
x
)
(
m
o
d
x
n
−
m
+
1
)
F(\frac{1}{x})=Q(\frac{1}{x})G(\frac{1}{x})+R(\frac{1}{x}) \\ F_R(x)=Q_R(x)G_R(x)+x^{n-m+1}R_R(x) \\ F_R(x)\equiv Q_R(x)G_R(x)(mod\ x^{n-m+1}) \\ Q_R(x)\equiv \frac{F_R(x)}{G_R(x)} (mod\ x^{n-m+1})
F(x1)=Q(x1)G(x1)+R(x1)FR(x)=QR(x)GR(x)+xn−m+1RR(x)FR(x)≡QR(x)GR(x)(mod xn−m+1)QR(x)≡GR(x)FR(x)(mod xn−m+1)
然后就是一波求逆, 然后带入原式即可得到
R
(
x
)
R(x)
R(x)。
代码如下:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <cstdlib>
#include <cctype>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define ll long long
#define MOD 998244353
#define g 3
#define ginv 332748118
#define MX 400500
template <class T>
IN void in(T &x)
{
x = 0; R char c = gc;
for (; !isdigit(c); c = gc);
for (; isdigit(c); c = gc)
x = (x << 1) + (x << 3) + c - 48;
}
IN int fpow(R int base, R int tim)
{
int ret = 1;
W (tim)
{
if (tim & 1) ret = 1ll * ret * base % MOD;
base = 1ll * base * base % MOD, tim >>= 1;
}
return ret;
}
int n, m;
int F[MX], G[MX], FR[MX], GR[MX], Q[MX], rev[MX], a[MX], b[MX], GRinv[MX], sur[MX];
namespace Poly
{
IN void NTT(int *dat, R int len, R int typ)
{
for (R int i = 1; i < len; ++i) if (rev[i] > i) std::swap(dat[rev[i]], dat[i]);
R int seg, step, bd, now, cur, buf1, buf2, base, deal;
for (seg = 1; seg < len; seg <<= 1)
{
base = fpow(typ ? g : ginv, (MOD - 1) / (seg << 1)), step = seg << 1;
for (now = 0; now < len; now += step)
{
bd = now + seg, deal = 1;
for (cur = now; cur < bd; ++cur, deal = 1ll * deal * base % MOD)
{
buf1 = dat[cur], buf2 = 1ll * dat[cur + seg] * deal % MOD;
dat[cur] = (buf1 + buf2) % MOD, dat[cur + seg] = (buf1 - buf2 + MOD) % MOD;
}
}
}
if (typ) return; int inv = fpow(len, MOD - 2);
for (R int i = 0; i < len; ++i) dat[i] = 1ll * dat[i] * inv % MOD;
}
void Getinv(R int up, R int lg, int *ans, int *ind)
{
if (up == 1) return ans[0] = fpow(ind[0], MOD - 2), void();
Getinv(up >> 1, lg - 1, ans, ind); R int len = up << 1;
for (R int i = 1; i < len; ++i) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << lg - 1);
for (R int i = 0; i < len; ++i) a[i] = b[i] = 0;
for (R int i = 0; i < up; ++i) a[i] = ans[i], b[i] = ind[i];
NTT(a, len, 1), NTT(b, len, 1);
for (R int i = 0; i < len; ++i) a[i] = (2 * a[i] % MOD - 1ll * b[i] * a[i] % MOD * a[i] % MOD + MOD) % MOD;
NTT(a, len, 0);
for (R int i = 0; i < up; ++i) ans[i] = a[i];
}
IN void Div(int n, int m)
{
int bd = n - m + 1, lg = 0, len = 1, up = n + m;
for (; len < bd; len <<= 1, lg++);
Getinv(len, lg + 1, GRinv, GR);
for (len = 1, lg = 0; len <= (bd << 1); len <<= 1, ++lg);
for (R int i = 1; i < len; ++i) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << lg - 1);
for (R int i = 0; i < len; ++i) a[i] = b[i] = 0;
for (R int i = 0; i < bd; ++i) a[i] = FR[i];
for (R int i = 0; i < bd; ++i) b[i] = GRinv[i];
NTT(a, len, 1), NTT(b, len, 1);
for (R int i = 0; i < len; ++i) a[i] = 1ll * a[i] * b[i] % MOD;
NTT(a, len, 0);
for (R int i = 0; i < bd; ++i) Q[i] = a[bd - 1 - i];
up = n; for (len = 1, lg = 0; len <= up; len <<= 1, ++lg);
for (R int i = 1; i < len; ++i) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << lg - 1);
for (R int i = 0; i < len; ++i) a[i] = b[i] = 0;
for (R int i = 0; i < bd; ++i) a[i] = Q[i];
for (R int i = 0; i <= m; ++i) b[i] = G[i];
NTT(a, len, 1), NTT(b, len, 1);
for (R int i = 0; i < len; ++i) a[i] = 1ll * a[i] * b[i] % MOD;
NTT(a, len, 0);
for (R int i = 0; i < m; ++i) sur[i] = (F[i] - a[i] + MOD) % MOD;
for (R int i = 0; i < bd; ++i) printf("%d ", Q[i]); puts("");
for (R int i = 0; i < m; ++i) printf("%d ", sur[i]);
}
}
int main(void)
{
in(n), in(m);
for (R int i = 0; i <= n; ++i) in(F[i]), FR[n - i] = F[i];
for (R int i = 0; i <= m; ++i) in(G[i]), GR[m - i] = G[i];
Poly::Div(n, m);
}