版权声明:欢迎转载蒟蒻博客,但请注明出处: https://blog.csdn.net/LPA20020220/article/details/85238458
洛谷传送门
题目描述
给定一个 次多项式 和一个 次多项式 ,请求出多项式 , ,满足以下条件:
- 次数为 , 次数小于
所有的运算在模 意义下进行。
输入输出格式
输入格式:
第一行两个整数
,
,意义如上。
第二行
个整数,从低到高表示
的各个系数。
第三行
个整数,从低到高表示
的各个系数。
输出格式:
第一行
个整数,从低到高表示
的各个系数。
第二行
个整数,从低到高表示
的各个系数。
如果
不足
次,多余的项系数补
。
输入输出样例
输入样例#1:
5 1
1 9 2 6 0 8
1 7
输出样例#1:
237340659 335104102 649004347 448191342 855638018
760903695
说明
对于所有数据, ,给出的系数均属于 。
解题分析
设 , 可以发现 和 的系数正好从大到小正好相反。
那么就有:
然后就是一波求逆, 然后带入原式即可得到
。
代码如下:
#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);
}