洛谷传送门
题目描述
给出 n − 1 n-1 n−1 次多项式 A ( x ) A(x) A(x),求一个   m o d     x n \bmod{\:x^n} modxn 下的多项式 B ( x ) B(x) B(x),满足 B ( x ) ≡ e A ( x ) B(x) \equiv e^{A(x)} B(x)≡eA(x).
输入输出格式
输入格式:
第一行一个整数 n n n.
下一行有 n n n 个整数,依次表示多项式的系数 a 0 , a 1 , ⋯   , a n − 1 a_0, a_1, \cdots, a_{n-1} a0,a1,⋯,an−1.
保证 a 0 = 0 a_0 = 0 a0=0.
输出格式:
输出 n n n 个整数,表示答案多项式中的系数 a 0 , a 1 , ⋯   , a n − 1 a_0, a_1, \cdots, a_{n-1} a0,a1,⋯,an−1.
输入输出样例
输入样例#1:
6
0 927384623 817976920 427326948 149643566 610586717
输出样例#1:
1 927384623 878326372 3882 273455637 998233543
说明
对于 100 % 100\% 100% 的数据, n ≤ 1 0 5 n \le 10^5 n≤105.
解题分析
为啥取 l n ln ln很简单, e x p exp exp这么难啊QAQ, 还得先去学牛顿迭代和泰勒展开。
推荐一篇讲泰勒展开的文章:戳这里
牛顿迭代是指这个:
假设我们已经知道了一个函数 G ( x ) G(x) G(x), 要求满足要求的 F ( x ) F(x) F(x), 满足 G ( F ( x ) ) ≡ 0 ( m o d x n ) G(F(x))\equiv 0(mod\ x^n) G(F(x))≡0(mod xn)。
这是有套路的。设
F
0
(
x
)
F_0(x)
F0(x)满足
G
(
F
0
(
x
)
)
≡
0
(
m
o
d
x
⌈
n
2
⌉
)
G(F_0(x))\equiv 0(mod\ x^{\lceil\frac{n}{2}\rceil})
G(F0(x))≡0(mod x⌈2n⌉), 那么怎么求得
F
(
x
)
F(x)
F(x)? 我们可以在
F
0
(
x
)
F_0(x)
F0(x)处泰勒展开, 得到:
G
(
F
(
x
)
)
=
G
(
F
0
(
x
)
)
+
G
′
(
F
0
(
x
)
)
1
!
(
F
(
x
)
−
F
0
(
x
)
)
+
G
′
′
(
F
0
(
x
)
)
2
!
(
F
(
x
)
−
F
0
(
x
)
)
2
+
.
.
.
+
G
∞
(
F
0
(
x
)
)
∞
(
F
(
x
)
−
F
0
(
x
)
)
∞
G(F(x))=G(F_0(x))+\frac{G'(F_0(x))}{1!}(F(x)-F_0(x))+\frac{G''(F_0(x))}{2!}(F(x)-F_0(x))^2+...+\frac{G^{\infin}(F_0(x))}{\infin}(F(x)-F_0(x))^{\infin}
G(F(x))=G(F0(x))+1!G′(F0(x))(F(x)−F0(x))+2!G′′(F0(x))(F(x)−F0(x))2+...+∞G∞(F0(x))(F(x)−F0(x))∞
注意到
F
(
x
)
−
F
0
(
x
)
F(x)-F_0(x)
F(x)−F0(x)的最低项都是
x
⌈
n
2
⌉
x^{\lceil\frac{n}{2}\rceil}
x⌈2n⌉, 所以后面的几项在模意义下都是0。即:
G
(
F
(
x
)
)
=
G
(
F
0
(
x
)
)
+
G
′
(
F
0
(
x
)
)
(
F
(
x
)
−
F
0
(
x
)
)
G(F(x))=G(F_0(x))+G'(F_0(x))(F(x)-F_0(x))
G(F(x))=G(F0(x))+G′(F0(x))(F(x)−F0(x))
又因为
G
(
F
(
x
)
)
≡
0
(
m
o
d
x
n
)
,
G(F(x))\equiv 0(mod\ x^n),
G(F(x))≡0(mod xn),移项得到:
F
(
x
)
=
−
G
(
F
0
(
x
)
)
G
′
(
F
0
(
x
)
)
+
F
0
(
x
)
F(x)=\frac{-G(F_0(x))}{G'(F_0(x))}+F_0(x)
F(x)=G′(F0(x))−G(F0(x))+F0(x)
递归下去, 当
n
=
1
n=1
n=1时暴力计算即可。
那么这里就有:
l
n
(
B
(
x
)
)
−
A
(
x
)
≡
0
(
m
o
d
x
n
)
ln(B(x))-A(x)\equiv 0(mod\ x^n)
ln(B(x))−A(x)≡0(mod xn)。
设
G
(
B
(
x
)
)
=
l
n
(
B
(
x
)
)
−
A
(
x
)
G(B(x))=ln(B(x))-A(x)
G(B(x))=ln(B(x))−A(x),那么根据上面的套路就有:
B
(
x
)
=
A
(
x
)
−
l
n
(
B
0
(
x
)
)
1
B
0
(
x
)
+
B
0
(
x
)
=
B
0
(
x
)
(
1
+
A
(
x
)
−
l
n
(
B
0
(
x
)
)
)
B(x)=\frac{A(x)-ln(B_0(x))}{\frac{1}{B_0(x)}}+B_0(x) \\ ={B_0(x)(1+A(x)-ln(B_0(x)))}
B(x)=B0(x)1A(x)−ln(B0(x))+B0(x)=B0(x)(1+A(x)−ln(B0(x)))
于是只需要写个求
l
n
ln
ln, 积分, 求导, 求逆即可。
代码如下:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <algorithm>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define MX 400500
#define MOD 998244353
#define G 3
#define Ginv 332748118
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;
int A[MX], ans[MX], rev[MX], buf[6][MX];
namespace Poly
{
IN void NTT(int *dat, R int len, R bool typ)
{
for (R int i = 0; i < len; ++i) if (rev[i] > i) std::swap(dat[i], dat[rev[i]]);
R int seg, step, bd, now, cur, base, deal, buf1, buf2;
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)
{
deal = 1, bd = now + seg;
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;
}
IN void Dr(int *dat, int *dr, R int len) {for (R int i = 1; i < len; ++i) dr[i - 1] = 1ll * i * dat[i] % MOD; dr[len] = 0;}
IN void Itg(int *dat, int *itg, R int len) {for (R int i = 1; i < len; ++i) itg[i] = 1ll * dat[i - 1] * fpow(i, MOD - 2) % MOD; itg[0] = 0;}
void Getinv(R int up, R int lg, int *ind, int *res, int *buf1, int *buf2)
{
if (up == 1) return res[0] = fpow(ind[0], MOD - 2), void();
Getinv(up >> 1, lg - 1, ind, res, buf1, buf2);
int len = up << 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) buf1[i] = buf2[i] = 0;
for (R int i = 0; i < (up >> 1); ++i) buf1[i] = res[i];
for (R int i = 0; i < up; ++i) buf2[i] = ind[i];
NTT(buf1, len, 1), NTT(buf2, len, 1);
for (R int i = 0; i < len; ++i) buf1[i] = (2 * buf1[i] % MOD - 1ll * buf2[i] * buf1[i] % MOD * buf1[i] % MOD + MOD) % MOD;
NTT(buf1, len, 0);
for (R int i = 0; i < up; ++i) res[i] = buf1[i];
}
IN void Getln(R int up, R int lg, int *ind, int *res, int *buf1, int *buf2, int *buf3, int *buf4)
{
for (R int i = 0; i <= up; ++i) buf1[i] = buf2[i] = 0;
Dr(ind, buf1, up);
Getinv(up, lg, ind, buf2, buf3, buf4);
int len = up << 1; lg++;
for (R int i = 1; i < len; ++i) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << lg - 1);
for (R int i = up; i < len; ++i) buf3[i] = buf4[i] = 0;
for (R int i = 0; i < up; ++i) buf3[i] = buf1[i], buf4[i] = buf2[i];
NTT(buf3, len, 1), NTT(buf4, len, 1);
for (R int i = 0; i < len; ++i) buf3[i] = 1ll * buf3[i] * buf4[i] % MOD;
NTT(buf3, len, 0); Itg(buf3, res, up);
}
IN void Getexp(R int up, R int lg)
{
if (up == 1) return ans[0] = 1, void();
int half = up >> 1; Getexp(half, lg - 1);
R int len = up << 1; lg++;
for (R int i = 0; i < len; ++i) buf[0][i] = buf[1][i] = 0;
for (R int i = 0; i < half; ++i) buf[0][i] = ans[i];
Getln(up, lg - 1, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
for (R int i = half; i < len; ++i) buf[2][i] = buf[3][i] = 0;
for (R int i = 0; i < half; ++i) buf[2][i] = ans[i];
for (R int i = 0; i < up; ++i) buf[3][i] = (A[i] - buf[1][i] + MOD) % MOD;
buf[3][0] = (buf[3][0] + 1) % MOD;
NTT(buf[2], len, 1), NTT(buf[3], len, 1);
for (R int i = 0; i < len; ++i) buf[2][i] = 1ll * buf[2][i] * buf[3][i] % MOD;
NTT(buf[2], len, 0);
for (R int i = 0; i < up; ++i) ans[i] = buf[2][i];
}
}
int main(void)
{
in(n); int len = 1, lg = 0;
for (; len < n; lg++, len <<= 1);
for (R int i = 0; i < n; ++i) in(A[i]);
Poly::Getexp(len, lg);
for (R int i = 0; i < n; ++i) printf("%d ", ans[i]);
}