多项式全家桶
多项式乘法
FFT
#include<cstdio>
#include<cmath>
#include<iostream>
using namespace std;
const double PI = acos(-1.0);
const int MAXN = 1e7 + 5;
inline int read() {
char ch;
while((ch = getchar()) && (ch < '0' || ch > '9'));
return ch - '0';
}
int n, m, len, lim = 1;
int r[MAXN];
struct complex {
double x, y;
complex (double xx = 0, double yy = 0) {x = xx, y = yy;}
complex operator + (complex b) {return complex(x + b.x, y + b.y);};
complex operator - (complex b) {return complex(x - b.x, y - b.y);};
complex operator * (complex b) {return complex(x * b.x - y * b.y, x * b.y + y * b.x);};
}f[MAXN], g[MAXN];
void FFT(complex *A, int op) {
for(int i = 0; i < lim; i++)
if(i < r[i]) swap(A[i], A[r[i]]);
for(int mid = 1; mid < lim; mid <<= 1) {
complex wn(cos(PI / mid), op * sin(PI / mid));
for(int r = mid << 1, j = 0; j < lim; j += r) {
complex w(1, 0);
for(int k = 0; k < mid; k++, w = w * wn) {
complex x = A[j + k], y = w * A[j + k + mid];
A[j + k] = x + y, A[j + k + mid] = x - y;
}
}
}
}
int main() {
scanf("%d%d",&n, &m);
for(int i = 0; i <= n; i++) f[i].x = read();
for(int i = 0; i <= m; i++) g[i].x = read();
len = n + m;
int l = 0;
while(lim <= n + m) lim <<= 1, l++;
for(int i = 0; i < lim; i++)
r[i] = (r[i >> 1] >> 1) | ((i & 1) << (l - 1));
FFT(f, 1);
FFT(g, 1);
for(int i = 0; i <= lim; i++) f[i] = f[i] * g[i];
FFT(f, -1);
for(int i = 0; i <= n + m; i++)
printf("%d ",(int)(f[i].x / lim + 0.5));
return 0;
}
NTT
#include<cstdio>
#include<iostream>
#define LL long long
using namespace std;
inline int read() {
int res = 0, f = 1; char ch;
while((ch = getchar()) && (ch < '0' || ch > '9') && ch != '0');
(ch == '0') ? f = -1 : res = ch - '0';
while((ch = getchar()) && ch >= '0' && ch <= '9') res = (res << 3) + (res << 1) + ch - '0';
return res * f;
}
int prnum[21];
inline void print(LL x) {
if(x == 0) putchar('0');
else {
if(x < 0) putchar('-'), x = -x;
register int prcnt = 0;
while(x) {
prnum[++prcnt] = x % 10;
x /= 10;
}
for(register int i = prcnt; i >= 1; i--) putchar(prnum[i] + '0');
}
}
const int MAXN = 1e6 + 5;
const LL P = 998244353, G = 3, Gi = 332748118;
int n, m;
int lim = 1, len, rev[MAXN << 2];
LL f[MAXN << 2], g[MAXN << 2];
inline LL expow(LL x, LL y) {
LL res = 1;
while(y) {
if(y & 1) res = res * x % P;
x = x * x % P, y >>= 1;
}
return res;
}
inline void NTT(LL *A, int op) {
for(int i = 0; i < lim; i++)
if(i > rev[i]) swap(A[i], A[rev[i]]);
for(int mid = 1; mid < lim; mid <<= 1) {
LL wn = expow((op == 1 ? G : Gi), (P - 1) / (mid << 1));
for(int r = (mid << 1), j = 0; j < lim; j += r) {
LL w = 1;
for(int k = 0; k < mid; k++, w = w * wn % P) {
LL x = A[j + k], y = w * A[j + k + mid] % P;
A[j + k] = (x + y) % P, A[j + k + mid] = ((x - y) % P + P) % P;
}
}
}
}
int main() {
n = read(); m = read();
for(int i = 0; i <= n; i++) f[i] = read();
for(int i = 0; i <= m; i++) g[i] = read();
while(lim <= n + m) lim <<= 1, ++len;
for(int i = 0; i < lim; i++)
rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (len - 1));
NTT(f, 1); NTT(g, 1);
for(int i = 0; i < lim; i++) f[i] = f[i] * g[i] % P;
NTT(f, -1);
LL inv = expow(lim, P - 2);
for(int i = 0; i <= n + m; i++)
print(f[i] * inv % P), putchar(' ');
return 0;
}
多项式乘法逆
求 g 使得 F∗G≡1 (mod xn)。
设 F∗H≡1 (mod x⌈n2⌉)。
两边同乘 F,得:
当递归到常数项时,H0 为 F0 在模 p 意义下的逆元。
#include<cstdio>
#include<iostream>
#define LL long long
using namespace std;
inline LL read() {
LL res = 0, f = 1; char ch;
while((ch = getchar()) && (ch < '0' || ch > '9') && ch != '-');
(ch == '-') ? f = -1 : res = ch - '0';
while((ch = getchar()) && ch >= '0' && ch <= '9') res = (res << 3) + (res << 1) + ch - '0';
return res * f;
}
int prnum[21];
inline void print(LL x) {
if(x == 0) putchar('0');
else {
register int prcnt = 0;
while(x) {
prnum[++prcnt] = x % 10;
x /= 10;
}
for(register int i = prcnt; i >= 1; i--) putchar(prnum[i] + '0');
}
}
const int MAXN = 4e5 + 5;
const LL MOD = 998244353, G = 3, Gi = 332748118;
int n, rev[MAXN];
LL f[MAXN], g[MAXN], c[MAXN];
inline LL expow(LL x, LL y) {
LL res = 1;
while(y) {
if(y & 1) res = res * x % MOD;
y >>= 1, x = x * x % MOD;
}
return res;
}
inline void NTT(LL *A, int lim, int op) {
for(int i = 0; i < lim; i++)
if(i > rev[i]) swap(A[i], A[rev[i]]);
for(int mid = 1; mid < lim; mid <<= 1) {
LL wn = expow((op == 1) ? G : Gi, (MOD - 1) / (mid << 1));
for(int r = (mid << 1), j = 0; j < lim; j += r) {
LL w = 1;
for(int k = 0; k < mid; k++, w = wn * w % MOD) {
LL x = A[j + k], y = w * A[j + k + mid] % MOD;
A[j + k] = (x + y) % MOD, A[j + k + mid] = ((x - y) % MOD + MOD) % MOD;
}
}
}
}
void solve(int len0, LL *a, LL *b) {
b[0] = expow(a[0], MOD - 2);
for(int len = 1; len < (len0 << 1); len <<= 1) {
int lim = 1, tot = 0;
while(lim < (len << 1)) lim <<= 1, ++tot;
for(int i = 1; i < lim; i++)
rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (tot - 1));
for(int i = 0; i < len; i++) c[i] = a[i];
for(int i = len; i < lim; i++) c[i] = 0;
NTT(c, lim, 1); NTT(b, lim, 1);
for(int i = 0; i < lim; i++)
b[i] = ((2 - c[i] * b[i]) % MOD * b[i] % MOD + MOD) % MOD;
NTT(b, lim, -1);
LL inv = expow(lim, MOD - 2);
for(int i = 0; i < len; i++) b[i] = b[i] * inv % MOD;
for(int i = len; i < lim; i++) b[i] = 0;
}
}
int main() {
n = read();
for(int i = 0; i < n; i++) f[i] = read();
solve(n, f, g);
for(int i = 0; i < n; i++) print(g[i]), putchar(' ');
return 0;
}
多项式开根
求 G 使得 G2≡F (mod xn)
设 H2≡F (mod x⌈n2⌉)
当递归到常数项时,令 H0 为 F0 在模 p 意义下的二次剩余。
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<ctime>
#define LL long long
using namespace std;
inline int read() {
int res = 0, f = 1; char ch;
while((ch = getchar()) && (ch < '0' || ch > '9') && ch != '-');
(ch == '-') ? f = -1 : res = ch - '0';
while((ch = getchar()) && ch >= '0' && ch <= '9') res = (res << 3) + (res << 1) + ch - '0';
return res * f;
}
int prnum[21];
inline void print(LL x) {
if(x == 0) putchar('0');
else {
register int prcnt = 0;
while(x) {
prnum[++prcnt] = x % 10;
x /= 10;
}
for(register int i = prcnt; i >= 1; i--) putchar(prnum[i] + '0');
}
}
const int MAXN = 4e5 + 5;
const LL MOD = 998244353, G = 3, Gi = 332748118, inv2 = 499122177;
int n, rev[MAXN];
LL pow_i, f[MAXN], g[MAXN], h[MAXN], q[MAXN], c[MAXN];
struct complex {
LL a, b;
};
inline complex operator * (const complex &x, const complex &y) { return (complex){(x.a * y.a % MOD + x.b * y.b % MOD * pow_i % MOD) % MOD, (x.a * y.b % MOD + x.b * y.a % MOD) % MOD}; }
inline int randmod() {
return 1ll * rand() * rand() % MOD;
}
inline LL expow(LL x, LL y) {
LL res = 1;
while(y) {
if(y & 1) res = res * x % MOD;
y >>= 1, x = x * x % MOD;
}
return res;
}
inline complex expow_i(complex x, int y) {
complex res = {1, 0};
while(y) {
if(y & 1) res = res * x;
y >>= 1, x = x * x;
}
return res;
}
inline LL cipolla(LL x) {
x %= MOD;
if(x == 0) return 0;
if(expow(x, (MOD - 1) / 2) == MOD - 1) return -1;
LL a, res;
while(1) {
a = randmod();
pow_i = ((a * a % MOD - x) % MOD + MOD) % MOD;
if(expow(pow_i, (MOD - 1) / 2) == MOD - 1) break;
}
res = expow_i((complex){a, 1}, (MOD + 1) / 2).a;
return min(res, MOD - res);
}
void NTT(LL *A, int lim, int op) {
for(int i = 0; i < lim; i++)
if(i > rev[i]) swap(A[i], A[rev[i]]);
for(int mid = 1; mid < lim; mid <<= 1) {
LL wn = expow((op == 1 ? G : Gi), (MOD - 1) / (mid << 1));
for(int r = (mid << 1), j = 0; j < lim; j += r) {
LL w = 1;
for(int k = 0; k < mid; k++, w = w * wn % MOD) {
LL x = A[j + k], y = w * A[j + k + mid];
A[j + k] = (x + y) % MOD, A[j + k + mid] = ((x - y) % MOD + MOD) % MOD;
}
}
}
}
void getinv(int len, LL *a, LL *b) {
if(len == 1) return b[0] = expow(a[0], MOD - 2), void();
getinv((len + 1) >> 1, a, b);
int lim = 1, tot = 0;
while(lim < (len << 1)) lim <<= 1, ++tot;
for(int i = 1; i < lim; i++)
rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (tot - 1));
for(int i = 0; i < len; i++) c[i] = a[i];
for(int i = len; i < lim; i++) c[i] = 0;
NTT(c, lim, 1); NTT(b, lim, 1);
for(int i = 0; i < lim; i++)
b[i] = ((2ll - c[i] * b[i] % MOD) * b[i] % MOD + MOD) % MOD;
NTT(b, lim, 0);
LL inv = expow(lim, MOD - 2);
for(int i = 0; i < len; i++) b[i] = b[i] * inv % MOD;
for(int i = len; i < lim; i++) b[i] = 0;
}
void getsqrt(int len, LL *a, LL *b) {
if(len == 1) return b[0] = cipolla(a[0]), void();
getsqrt((len + 1) >> 1, a, b);
int lim = 1, tot = 0;
while(lim < (len << 1)) lim <<= 1, ++tot;
for(int i = 0; i < lim; i++) h[i] = 0;
getinv(len, b, h);
for(int i = 1; i < lim; i++)
rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (tot - 1));
for(int i = 0; i < len; i++) q[i] = a[i];
for(int i = len; i < lim; i++) q[i] = 0;
NTT(q, lim, 1); NTT(h, lim, 1);
for(int i = 0; i < lim; i++) q[i] = q[i] * h[i] % MOD;
NTT(q, lim, 0);
LL inv = expow(lim, MOD - 2);
for(int i = 0; i < len; i++) b[i] = (b[i] + q[i] * inv % MOD) % MOD * inv2 % MOD;
for(int i = len; i < lim; i++) b[i] = 0;
}
int main() {
srand((unsigned)time(0));
n = read();
for(int i = 0; i < n; i++) f[i] = read();
getsqrt(n, f, g);
for(int i = 0; i < n; i++) print(g[i]), putchar(' ');
return 0;
}
多项式除法
求 Q,R,使得 F(x)≡G(x)∗Q(x)+R(x) (mod xn)(F(x)共n项,G(x)共m项)
若消除 R(x) 的影响,则可以直接通过多项式乘法逆求出 G(x),再直接代入,即可求出 R(x)。
设 AR(x)=xdegFA(1x)。
因为 Q(x) 仅有 n−m 项,所以模 xn−m+1 并不影响。
所以先求出 GR(x) 的逆,再做多项式乘法求出 Q(x)。
然后,通过
求出 R(x)。
写的时候注意边界问题,及时清零。
#include<cstdio>
#include<algorithm>
#define LL long long
using namespace std;
inline int read() {
int res = 0, f = 1; char ch;
while((ch = getchar()) && (ch < '0' || ch > '9') && ch != '0');
(ch == '0') ? f = -1 : res = ch - '0';
while((ch = getchar()) && ch >= '0' && ch <= '9') res = (res << 3) + (res << 1) + ch - '0';
return res * f;
}
int prnum[21];
inline void print(LL x) {
if(x == 0) putchar('0');
else {
if(x < 0) putchar('-'), x = -x;
register int prcnt = 0;
while(x) {
prnum[++prcnt] = x % 10;
x /= 10;
}
for(register int i = prcnt; i >= 1; i--) putchar(prnum[i] + '0');
}
}
const int MAXN = 4e5 + 5;
const LL MOD = 998244353, G = 3, Gi = 332748118;
int n, m, rev[MAXN];
LL f[MAXN], g[MAXN], g0[MAXN], gr[MAXN], q[MAXN], c[MAXN];
inline LL expow(LL x, LL y) {
LL res = 1;
while(y) {
if(y & 1) res = res * x % MOD;
y >>= 1, x = x * x % MOD;
}
return res;
}
inline void NTT(LL *A, int lim, int op) {
for(int i = 0; i < lim; i++)
if(i > rev[i]) swap(A[i], A[rev[i]]);
for(int mid = 1; mid < lim; mid <<= 1) {
LL wn = expow((op == 1 ? G : Gi), (MOD - 1) / (mid << 1));
for(int r = (mid << 1), j = 0; j < lim; j += r) {
LL w = 1;
for(int k = 0; k < mid; k++, w = w * wn % MOD) {
LL x = A[j + k], y = w * A[j + k + mid] % MOD;
A[j + k] = (x + y) % MOD, A[j + k + mid] = ((x - y) % MOD + MOD) % MOD;
}
}
}
}
void getinv(int len, LL *a, LL *b) {
if(len == 1) return b[0] = expow(a[0], MOD - 2), void();
getinv((len + 1) >> 1, a, b);
int lim = 1, tot = 0;
while(lim < (len << 1)) lim <<= 1, ++tot;
for(int i = 1; i < lim; i++)
rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (tot - 1));
for(int i = 0; i < len; i++) c[i] = a[i];
for(int i = len; i < lim; i++) c[i] = 0;
NTT(c, lim, 1); NTT(b, lim, 1);
for(int i = 0; i < lim; i++)
b[i] = ((2 - c[i] * b[i]) % MOD * b[i] % MOD + MOD) % MOD;
NTT(b, lim, -1);
LL inv = expow(lim, MOD - 2);
for(int i = 0; i < len; i++) b[i] = b[i] * inv % MOD;
for(int i = len; i < lim; i++) b[i] = 0;
}
void getmul(int lena, int lenb, int lenx, LL *a, LL *b) {
int lim = 1, tot = 0;
while(lim <= (lena + lenb)) lim <<= 1, ++tot;
for(int i = 1; i < lim; i++)
rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (tot - 1));
NTT(a, lim, 1); NTT(b, lim, 1);
for(int i = 0; i < lim; i++) a[i] = a[i] * b[i] % MOD;
NTT(a, lim, -1);
LL inv = expow(lim, MOD - 2);
for(int i = 0; i <= lenx; i++) a[i] = a[i] * inv % MOD;
for(int i = lenx + 1; i < lim; i++) a[i] = 0;
}
int main() {
n = read(); m = read();
for(int i = 0; i <= n; i++) f[i] = q[n - i] = read();
for(int i = 0; i <= m; i++) g[i] = read(), g0[m - i] = g[i];
for(int i = n - m + 1; i <= m; i++) g0[i] = 0;
getinv(n - m + 1, g0, gr);
getmul(n, n - m, n - m, q, gr);
reverse(q, q + n - m + 1);
for(int i = 0; i <= n - m; i++) print(q[i]), putchar(' '); putchar('\n');
getmul(m, n - m, m, g, q);
for(int i = 0; i < m; i++) print(((f[i] - g[i]) % MOD + MOD) % MOD), putchar(' '); putchar('\n');
return 0;
}
多项式牛顿迭代
前置芝士
1.乘法求导法则:
2.链式求导法则:
3.可以 O(n) 对一个多项式进行求导和积分。设 f(x)=∑iaixi,则
- f(x) 在 a 处的泰勒展开为:
描述
给定 g(x),已知 f(x) 满足:
求在模 xn 意义下的 f(x)。
牛顿迭代
倍增。
当 n=1 时,[x0]g(f(x)) 可求。
设 f(x) 在模 x⌈n2⌉ 意义下的解为 f0(x),要求在模 xn 意义下的解 f(x)。
将 g(f(x)) 在 f0(x) 处进行泰勒展开,得:
因为 f(x)−f0(x) 的最低非零项次数为 ⌈n2⌉,所以
所以
所以
应用
多项式求逆
给定 h(x),求 f(x)=h−1(x)。
设g(f(x))=1f(x)−h(x),所以
多项式开方,除法等也可用此方法推出,不过咕咕咕。
多项式对数函数
这个东西不需要牛顿迭代,只是 exp 的前置知识。
给定 f(x),求 ln(f(x))。
根据定义,若 ln(f(x)) 存在,则必须满足:
对 ln(f(x)) 求导再积分,得:
#include<cstdio>
#include<iostream>
#define LL long long
using namespace std;
inline LL read() {
LL res = 0, f = 1; char ch;
while((ch = getchar()) && (ch < '0' || ch > '9') && ch != '-');
(ch == '-') ? f = -1 : res = ch - '0';
while((ch = getchar()) && ch >= '0' && ch <= '9') res = (res << 3) + (res << 1) + ch - '0';
return res * f;
}
int prnum[21];
inline void print(LL x) {
if(x == 0) putchar('0');
else {
register int prcnt = 0;
while(x) {
prnum[++prcnt] = x % 10;
x /= 10;
}
for(register int i = prcnt; i >= 1; i--) putchar(prnum[i] + '0');
}
}
const int MAXN = 4e5 + 5;
const LL MOD = 998244353, G = 3, Gi = 332748118;
int n, rev[MAXN];
LL f[MAXN], g[MAXN], c[MAXN];
inline LL expow(LL x, LL y) {
LL res = 1;
while(y) {
if(y & 1) res = res * x % MOD;
y >>= 1, x = x * x % MOD;
}
return res;
}
inline void NTT(LL *A, int lim, int op) {
for(int i = 0; i < lim; i++)
if(i > rev[i]) swap(A[i], A[rev[i]]);
for(int mid = 1; mid < lim; mid <<= 1) {
LL wn = expow((op == 1) ? G : Gi, (MOD - 1) / (mid << 1));
for(int r = (mid << 1), j = 0; j < lim; j += r) {
LL w = 1;
for(int k = 0; k < mid; k++, w = w * wn % MOD) {
LL x = A[j + k], y = w * A[j + k + mid] % MOD;
A[j + k] = (x + y) % MOD, A[j + k + mid] = ((x - y) % MOD + MOD) % MOD;
}
}
}
}
void getinv(int len, LL *a, LL *b) {
if(len == 1) return b[0] = expow(a[0], MOD - 2), void();
getinv((len + 1) >> 1, a, b);
int lim = 1, tot = 0;
while(lim < (len << 1)) lim <<= 1, ++tot;
for(int i = 1; i < lim; i++)
rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (tot - 1));
for(int i = 0; i < len; i++) c[i] = a[i];
for(int i = len; i < lim; i++) c[i] = 0;
NTT(c, lim, 1); NTT(b, lim, 1);
for(int i = 0; i < lim; i++)
b[i] = ((2 - c[i] * b[i]) % MOD * b[i] % MOD + MOD) % MOD;
NTT(b, lim, -1);
LL inv = expow(lim, MOD - 2);
for(int i = 0; i < len; i++) b[i] = b[i] * inv % MOD;
for(int i = len; i < lim; i++) b[i] = 0;
}
void getln(int len, LL *a, LL *b) {
int lim = 1, tot = 0;
while(lim < (len << 1)) lim <<= 1, ++tot;
for(int i = 1; i < lim; i++)
rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (tot - 1));
for(int i = 1; i < len; i++) c[i - 1] = a[i] * i % MOD; c[len - 1] = 0;
for(int i = len; i < lim; i++) c[i] = 0;
NTT(c, lim, 1); NTT(b, lim, 1);
for(int i = 0; i < lim; i++) b[i] = c[i] * b[i] % MOD;
NTT(b, lim, -1);
LL inv = expow(lim, MOD - 2);
for(int i = len - 1; i >= 1; i--) b[i] = b[i - 1] * inv % MOD * expow(i, MOD - 2) % MOD; b[0] = 0;
for(int i = len; i < lim; i++) b[i] = 0;
}
int main() {
n = read();
for(int i = 0; i < n; i++) f[i] = read();
getinv(n, f, g);
getln(n, f, g);
for(int i = 0; i < n; i++) print(g[i]), putchar(' ');
return 0;
}
多项式指数函数
给定 h(x),求 f(x)=eh(x)。
设 g(f(x))=ln(f(x))−h(x),所以
#include<cstdio>
#include<iostream>
#define LL long long
using namespace std;
inline LL read() {
LL res = 0, f = 1; char ch;
while((ch = getchar()) && (ch < '0' || ch > '9') && ch != '-');
(ch == '-') ? f = -1 : res = ch - '0';
while((ch = getchar()) && ch >= '0' && ch <= '9') res = (res << 3) + (res << 1) + ch - '0';
return res * f;
}
int prnum[21];
inline void print(LL x) {
if(x == 0) putchar('0');
else {
register int prcnt = 0;
while(x) {
prnum[++prcnt] = x % 10;
x /= 10;
}
for(register int i = prcnt; i >= 1; i--) putchar(prnum[i] + '0');
}
}
const int MAXN = 4e5 + 5;
const LL MOD = 998244353, G = 3, Gi = 332748118;
int n, rev[MAXN];
LL f[MAXN], g[MAXN], h[MAXN], c[MAXN];
inline LL expow(LL x, LL y) {
LL res = 1;
while(y) {
if(y & 1) res = res * x % MOD;
y >>= 1, x = x * x % MOD;
}
return res;
}
inline void NTT(LL *A, int lim, int op) {
for(int i = 1; i < lim; i++)
if(i > rev[i]) swap(A[i], A[rev[i]]);
for(int mid = 1; mid < lim; mid <<= 1) {
LL wn = expow((op == 1) ? G : Gi, (MOD - 1) / (mid << 1));
for(int r = (mid << 1), j = 0; j < lim; j += r) {
LL w = 1;
for(int k = 0; k < mid; k++, w = w * wn % MOD) {
LL x = A[j + k], y = w * A[j + k + mid] % MOD;
A[j + k] = (x + y) % MOD, A[j + k + mid] = ((x - y) % MOD + MOD) % MOD;
}
}
}
}
void getinv(int len, LL *a, LL *b) {
if(len == 1) return b[0] = expow(a[0], MOD - 2), void();
getinv((len + 1) >> 1, a, b);
int lim = 1, tot = 0;
while(lim < (len << 1)) lim <<= 1, ++tot;
for(int i = 1; i < lim; i++)
rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (tot - 1));
for(int i = 0; i < len; i++) c[i] = a[i];
for(int i = len; i < lim; i++) c[i] = 0;
NTT(c, lim, 1); NTT(b, lim, 1);
for(int i = 0; i < lim; i++)
b[i] = ((2 - b[i] * c[i]) % MOD * b[i] % MOD + MOD) % MOD;
NTT(b, lim, -1);
LL inv = expow(lim, MOD - 2);
for(int i = 0; i < len; i++) b[i] = b[i] * inv % MOD;
for(int i = len; i < lim; i++) b[i] = 0;
}
void getln(int len, LL *a, LL *b) {
int lim = 1, tot = 0;
while(lim < (len << 1)) lim <<= 1, ++tot;
for(int i = 1; i < lim; i++)
rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (tot - 1));
for(int i = 1; i < len; i++) c[i - 1] = a[i] * i % MOD; c[len - 1] = 0;
for(int i = len; i < lim; i++) c[i] = 0;
NTT(c, lim, 1); NTT(b, lim, 1);
for(int i = 0; i < lim; i++) b[i] = c[i] * b[i] % MOD;
NTT(b, lim, -1);
LL inv = expow(lim, MOD - 2);
for(int i = len - 1; i >= 1; i--) b[i] = b[i - 1] * inv % MOD * expow(i, MOD - 2) % MOD; b[0] = 0;
for(int i = len; i < lim; i++) b[i] = 0;
}
void getexp(int len, LL *a, LL *b) {
if(len == 1) return b[0] = 1, void();
getexp((len + 1) >> 1, a, b);
int lim = 1, tot = 0;
while(lim < (len << 1)) lim <<= 1, ++tot;
for(int i = 0; i < lim; i++) h[i] = 0;
getinv(len, b, h); getln(len, b, h);
for(int i = 1; i < lim; i++)
rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (tot - 1));
h[0] = ((1 - h[0] + a[0]) % MOD + MOD) % MOD;
for(int i = 1; i < len; i++)
h[i] = ((a[i] - h[i]) % MOD + MOD) % MOD;
NTT(h, lim, 1); NTT(b, lim, 1);
for(int i = 0; i < lim; i++) b[i] = b[i] * h[i] % MOD;
NTT(b, lim, -1);
LL inv = expow(lim, MOD - 2);
for(int i = 0; i < len; i++) b[i] = b[i] * inv % MOD;
for(int i = len; i < lim; i++) b[i] = 0;
}
int main() {
n = read();
for(int i = 0; i < n; i++) f[i] = read();
getexp(n, f, g);
for(int i = 0; i < n; i++) print(g[i]), putchar(' ');
return 0;
}
__EOF__

本文链接:https://www.cnblogs.com/zym417/p/15831852.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?