【笔记】从零开始的多项式学习
【模板】多项式乘法#
板子,基础。
#define N 2097160
inline int ck(int x){return x >= P ? x - P : x; }
int t, rev[N];
void ntt(int *a,int op){
rp(i, t - 1)if(rev[i] < i)swap(a[i], a[rev[i]]);
for(int k = 2, l = 1; k <= t; k <<= 1, l <<= 1){
int g = Pow(op ? 3 : Q, (P - 1) / k);
for(int i = 0; i < t; i += k){
LL cur = 1;
rep(j, 0, l - 1){
int x = a[i + j], y = a[i + l + j] * cur % P;
a[i + j] = ck(x + y), a[i + l + j] = ck(x - y + P);
cur = cur * g % P;
}
}
}
}
void mul(int *u,int *v,int *w,int n,int m){
t = 1; while(t <= n + m)t <<= 1;
rp(i, t - 1)rev[i] = (rev[i >> 1] >> 1) | ((i & 1) ? (t >> 1) : 0);
ntt(u, 1), ntt(v, 1);
rep(i, 0, t)w[i] = u[i] * (LL)v[i] % P;
ntt(w, 0); LL iv = Pow(t, P - 2);
rep(i, 0, t)w[i] = w[i] * iv % P;
}
int n, m, u[N], v[N], w[N];
int main() {
read(n, m);
rep(i, 0, n)read(u[i]);
rep(i, 0, m)read(v[i]);
mul(u, v, w, n, m);
rep(i, 0, n + m)printf("%d ", ck(w[i] + P)); el;
return 0;
}
【模板】多项式求逆#
倍增解决。
#define N 270005
int rev[N], t;
inline int ck(int x){return x >= P ? x - P : x; }
void ntt(int *a,int op){
rp(i, t - 1)if(rev[i] < i)swap(a[i], a[rev[i]]);
for(int k = 2, l = 1; k <= t; k <<= 1, l <<= 1){
int g = Pow(op ? 3 : Q, (P - 1) / k);
for(int i = 0; i < t; i += k){
LL cur = 1;
rep(j, 0, l - 1){
int x = a[i + j], y = a[i + l + j] * cur % P;
a[i + j] = ck(x + y), a[i + l + j] = ck(x - y + P);
cur = cur * g % P;
}
}
}
}
int p[N];
void solve(int *u,int *v,int n){
if(1 == n){ v[0] = Pow(u[0], P - 2); return ;}
int m = (n + 1) / 2;
solve(u, v, m), t = 1;
while(t <= n + n)t <<= 1;
rp(i, t - 1)rev[i] = (rev[i >> 1] >> 1) | ((i & 1) ? (t >> 1) : 0);
rep(i, 0, t - 1)p[i] = 0;
rep(i, 0, n - 1)p[i] = u[i];
ntt(p, 1), ntt(v, 1);
rep(i, 0, t - 1)v[i] = v[i] * (2 - p[i] * (LL)v[i] % P + P) % P;
ntt(v, 0); LL iv = Pow(t, P - 2);
rep(i, 0, n - 1)v[i] = v[i] * iv % P;
rep(i, n, t - 1)v[i] = 0;
}
int n, a[N], b[N];
int main() {
read(n);
rep(i, 0, n - 1)read(a[i]);
solve(a, b, n);
rep(i, 0, n - 1)printf("%d ", b[i]);
return 0;
}
【模板】多项式对数函数#
求 ,先求导再积分,得到 ,套一个多项式求逆板子即可。
#define N 270005
int rev[N], t;
inline int ck(int x){return x >= P ? x - P : x; }
void ntt(int *a,int op){
rp(i, t - 1)if(rev[i] < i)swap(a[i], a[rev[i]]);
for(int k = 2, l = 1; k <= t; k <<= 1, l <<= 1){
int g = Pow(op ? 3 : Q, (P - 1) / k);
for(int i = 0; i < t; i += k){
LL cur = 1;
rep(j, 0, l - 1){
int x = a[i + j], y = a[i + l + j] * cur % P;
a[i + j] = ck(x + y), a[i + l + j] = ck(x - y + P);
cur = cur * g % P;
}
}
}
}
void mul(int *u,int *v,int *w,int lm){
t = 1; while(t <= lm)t <<= 1;
rp(i, t - 1)rev[i] = (rev[i >> 1] >> 1) | ((i & 1) ? (t >> 1) : 0);
ntt(u, 1), ntt(v, 1);
rep(i, 0, t)w[i] = u[i] * (LL)v[i] % P;
ntt(w, 0); LL iv = Pow(t, P - 2);
rep(i, 0, t)w[i] = w[i] * iv % P;
}
int p[N];
void solve(int *u,int *v,int n){
if(1 == n){ v[0] = Pow(u[0], P - 2); return ;}
int m = (n + 1) / 2;
solve(u, v, m), t = 1;
while(t <= n + n)t <<= 1;
rp(i, t - 1)rev[i] = (rev[i >> 1] >> 1) | ((i & 1) ? (t >> 1) : 0);
rep(i, 0, t - 1)p[i] = 0;
rep(i, 0, n - 1)p[i] = u[i];
ntt(p, 1), ntt(v, 1);
rep(i, 0, t - 1)v[i] = v[i] * (2 - p[i] * (LL)v[i] % P + P) % P;
ntt(v, 0); LL iv = Pow(t, P - 2);
rep(i, 0, n - 1)v[i] = v[i] * iv % P;
rep(i, n, t - 1)v[i] = 0;
}
int n, a[N], b[N], c[N], g[N];
int main() {
read(n);
rep(i, 0, n - 1)read(a[i]);
solve(a, b, n);
rp(i, n - 1)c[i - 1] = a[i] * (LL)i % P;
mul(b, c, g, n + n - 2);
pc('0'), pc(' ');
rp(i, n - 1)printf("%lld ", g[i - 1] * (LL)Pow(i, P - 2) % P);
return 0;
}
泰勒展开#
对于可导函数 ,有
牛顿迭代#
已知多项式 ,和条件:
另 ,我们求出在 意义下的解 ,然后再 处泰勒展开。由于 和 最低 项是相同的,所以在 时 。所以我们得到:
【模板】多项式指数函数#
求 ,构造函数 ,有 ,直接牛顿迭代得到 ,化简后得到 :
倍增即可,套一个多项式 ln 的板子。
#define N 270005
int rev[N], t;
inline int ck(int x){return x >= P ? x - P : x; }
void ntt(int *a,int op){
rp(i, t - 1)if(rev[i] < i)swap(a[i], a[rev[i]]);
for(int k = 2, l = 1; k <= t; k <<= 1, l <<= 1){
int g = Pow(op ? 3 : Q, (P - 1) / k);
for(int i = 0; i < t; i += k){
LL cur = 1;
rep(j, 0, l - 1){
int x = a[i + j], y = a[i + l + j] * cur % P;
a[i + j] = ck(x + y), a[i + l + j] = ck(x - y + P);
cur = cur * g % P;
}
}
}
}
void mul(int *u,int *v,int *w,int lm){
t = 1; while(t <= lm)t <<= 1;
rp(i, t - 1)rev[i] = (rev[i >> 1] >> 1) | ((i & 1) ? (t >> 1) : 0);
ntt(u, 1), ntt(v, 1);
rep(i, 0, t)w[i] = u[i] * (LL)v[i] % P;
ntt(w, 0); LL iv = Pow(t, P - 2);
rep(i, 0, t)w[i] = w[i] * iv % P;
}
int p[N];
void solve(int *u,int *v,int n){
if(1 == n){ v[0] = Pow(u[0], P - 2); return ;}
int m = (n + 1) / 2;
solve(u, v, m), t = 1;
while(t <= n + n)t <<= 1;
rp(i, t - 1)rev[i] = (rev[i >> 1] >> 1) | ((i & 1) ? (t >> 1) : 0);
rep(i, 0, t - 1)p[i] = 0;
rep(i, 0, n - 1)p[i] = u[i];
ntt(p, 1), ntt(v, 1);
rep(i, 0, t - 1)v[i] = v[i] * (2 - p[i] * (LL)v[i] % P + P) % P;
ntt(v, 0); LL iv = Pow(t, P - 2);
rep(i, 0, n - 1)v[i] = v[i] * iv % P;
rep(i, n, t - 1)v[i] = 0;
}
int b[N], c[N], iv[N];
void polyln(int *a,int *g,int n){
t = 1; while(t <= n + n)t <<= 1;
rep(i, 0, t - 1)b[i] = c[i] = 0;
solve(a, b, n);
rp(i, n - 1)c[i - 1] = a[i] * (LL)i % P;
mul(b, c, g, n + n - 2);
pr(i, n - 1)g[i] = g[i - 1] * (LL)iv[i] % P;
g[0] = 0;
}
int w[N], f[N];
void polyexp(int *a,int *u,int n){
if(1 == n){u[0] = 1; return;}
int m = (n + 1) / 2;
polyexp(a, u, m), polyln(u, f, n);
rep(i, 0, n - 1)f[i] = ck(a[i] + (i == 0) - f[i] + P);
mul(f, u, w, n + n - 2);
rep(i, 0, n - 1)u[i] = w[i];
rep(i, n, t - 1)u[i] = 0;
}
int n, a[N], g[N];
int main() {
read(n);
rep(i, 0, n - 1)read(a[i]);
iv[1] = 1; rep(i, 2, n)iv[i] = P - (P / i) * (LL)iv[P % i] % P;
polyexp(a, g, n);
rep(i, 0, n - 1)printf("%d ", g[i]);
return 0;
}
【模板】多项式快速幂#
求 ,取多项式 得到 ,然后再 回去即可。
#define N 270005
int rev[N], t;
inline int ck(int x){return x >= P ? x - P : x; }
void ntt(int *a,int op){
rp(i, t - 1)if(rev[i] < i)swap(a[i], a[rev[i]]);
for(int k = 2, l = 1; k <= t; k <<= 1, l <<= 1){
int g = Pow(op ? 3 : Q, (P - 1) / k);
for(int i = 0; i < t; i += k){
LL cur = 1;
rep(j, 0, l - 1){
int x = a[i + j], y = a[i + l + j] * cur % P;
a[i + j] = ck(x + y), a[i + l + j] = ck(x - y + P);
cur = cur * g % P;
}
}
}
}
void mul(int *u,int *v,int *w,int lm){
t = 1; while(t <= lm)t <<= 1;
rp(i, t - 1)rev[i] = (rev[i >> 1] >> 1) | ((i & 1) ? (t >> 1) : 0);
ntt(u, 1), ntt(v, 1);
rep(i, 0, t)w[i] = u[i] * (LL)v[i] % P;
ntt(w, 0); LL iv = Pow(t, P - 2);
rep(i, 0, t)w[i] = w[i] * iv % P;
}
int p[N];
void solve(int *u,int *v,int n){
if(1 == n){ v[0] = Pow(u[0], P - 2); return ;}
int m = (n + 1) / 2;
solve(u, v, m), t = 1;
while(t <= n + n)t <<= 1;
rp(i, t - 1)rev[i] = (rev[i >> 1] >> 1) | ((i & 1) ? (t >> 1) : 0);
rep(i, 0, t - 1)p[i] = 0;
rep(i, 0, n - 1)p[i] = u[i];
ntt(p, 1), ntt(v, 1);
rep(i, 0, t - 1)v[i] = v[i] * (2 - p[i] * (LL)v[i] % P + P) % P;
ntt(v, 0); LL iv = Pow(t, P - 2);
rep(i, 0, n - 1)v[i] = v[i] * iv % P;
rep(i, n, t - 1)v[i] = 0;
}
int b[N], c[N], iv[N];
void polyln(int *a,int *g,int n){
t = 1; while(t <= n + n)t <<= 1;
rep(i, 0, t - 1)b[i] = c[i] = 0;
solve(a, b, n);
rp(i, n - 1)c[i - 1] = a[i] * (LL)i % P;
mul(b, c, g, n + n - 2);
pr(i, n - 1)g[i] = g[i - 1] * (LL)iv[i] % P;
g[0] = 0;
}
int w[N], f[N];
void polyexp(int *a,int *u,int n){
if(1 == n){u[0] = 1; return;}
int m = (n + 1) / 2;
polyexp(a, u, m), polyln(u, f, n);
rep(i, 0, n - 1)f[i] = ck(a[i] + (i == 0) - f[i] + P);
mul(f, u, w, n + n - 2);
rep(i, 0, n - 1)u[i] = w[i];
rep(i, n, t - 1)u[i] = 0;
}
int n, k, a[N], g[N], h[N];
int main() {
read(n, k);
rep(i, 0, n - 1)read(a[i]);
iv[1] = 1; rep(i, 2, n)iv[i] = P - (P / i) * (LL)iv[P % i] % P;
polyln(a, h, n);
rep(i, 0, n - 1)h[i] = h[i] * (LL)k % P;
polyexp(h, g, n);
rep(i, 0, n - 1)printf("%d ", g[i]);
return 0;
}
【模板】多项式开根#
构造 ,有 ,直接牛顿迭代即可,套一个多项式求逆的板子。
#define N 270005
int rev[N], t;
inline int ck(int x){return x >= P ? x - P : x; }
void ntt(int *a,int op){
rp(i, t - 1)if(rev[i] < i)swap(a[i], a[rev[i]]);
for(int k = 2, l = 1; k <= t; k <<= 1, l <<= 1){
int g = Pow(op ? 3 : Q, (P - 1) / k);
for(int i = 0; i < t; i += k){
LL cur = 1;
rep(j, 0, l - 1){
int x = a[i + j], y = a[i + l + j] * cur % P;
a[i + j] = ck(x + y), a[i + l + j] = ck(x - y + P);
cur = cur * g % P;
}
}
}
}
void mul(int *u,int *v,int *w,int lm){
t = 1; while(t <= lm)t <<= 1;
rp(i, t - 1)rev[i] = (rev[i >> 1] >> 1) | ((i & 1) ? (t >> 1) : 0);
ntt(u, 1), ntt(v, 1);
rep(i, 0, t)w[i] = u[i] * (LL)v[i] % P;
ntt(w, 0); LL iv = Pow(t, P - 2);
rep(i, 0, t)w[i] = w[i] * iv % P;
}
int p[N];
void solve(int *u,int *v,int n){
if(1 == n){ v[0] = Pow(u[0], P - 2); return ;}
int m = (n + 1) / 2;
solve(u, v, m), t = 1;
while(t <= n + n)t <<= 1;
rp(i, t - 1)rev[i] = (rev[i >> 1] >> 1) | ((i & 1) ? (t >> 1) : 0);
rep(i, 0, t - 1)p[i] = 0;
rep(i, 0, n - 1)p[i] = u[i];
ntt(p, 1), ntt(v, 1);
rep(i, 0, t - 1)v[i] = v[i] * (2 - p[i] * (LL)v[i] % P + P) % P;
ntt(v, 0); LL iv = Pow(t, P - 2);
rep(i, 0, n - 1)v[i] = v[i] * iv % P;
rep(i, n, t - 1)v[i] = 0;
}
int l[N], c[N], d[N];
void sqr(int *u,int *v,int n){
if(1 == n){v[0] = 1; return ;}
int m = (n + 1) / 2;
sqr(u, v, m), t = 1;
while(t <= n + n)t <<= 1;
rep(i, 0, t - 1)l[i] = c[i] = d[i] = 0;
rep(i, 0, n - 1)l[i] = v[i];
solve(v, c, n),
mul(l, v, d, n + n);
rep(i, 0, n - 1)ad(d[i], u[i]);
rep(i, n, t - 1)d[i] = 0;
mul(d, c, v, n + n);
rep(i, 0, n - 1)v[i] = v[i] * (LL)I % P;
rep(i, n, t - 1)v[i] = 0;
}
int n, a[N], b[N];
int main() {
read(n);
rep(i, 0, n - 1)read(a[i]);
sqr(a, b, n);
rep(i, 0, n - 1)printf("%d ", b[i]);
return 0;
}
作者:7KByte
出处:https://www.cnblogs.com/7KByte/p/16635424.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
2021-08-29 【模板】最小斯坦纳树