【笔记】从零开始的多项式学习

【模板】多项式乘法#

板子,基础。

#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;
}

【模板】多项式对数函数#

ln(F(x)),先求导再积分,得到 ln(F(x))=F(x)F(x),套一个多项式求逆板子即可。

#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;
}

泰勒展开#

对于可导函数 f,有

f(x)=i0f(i)(x0)i!(xx0)i

牛顿迭代#

已知多项式 g(x),和条件:

g(f(x))0(modxn)

m=n+12,我们求出在 modxm 意义下的解 f0(x),然后再 f0(x) 处泰勒展开。由于 f(x)f0(x) 最低 m 项是相同的,所以在 i2(f(x)f0(x))i0(modxn)。所以我们得到:

f(x)f0(x)g(f0(x))g(f0(x))(modxn)

【模板】多项式指数函数#

G(x)=exp(F(x)),构造函数 g(f(x))=lnf(x)F(x),有 g(G(x))0,直接牛顿迭代得到 G(x)G0(x)ln(G0(x))F(x)1/(G0(x)),化简后得到 :

G(x)=G0(x)(1lnG0(x)+F(x))

倍增即可,套一个多项式 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;
}

【模板】多项式快速幂#

Fk(x),取多项式 ln 得到 lnFk(x)=klnF(x),然后再 exp 回去即可。

#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;
}

【模板】多项式开根#

构造 g(f(x))=f2(x)A(x),有 g(B(x))0,直接牛顿迭代即可,套一个多项式求逆的板子。

B(x)=B02(x)+A(x)2B0(x)

#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 国际」许可协议进行许可。

posted @   7KByte  阅读(238)  评论(2编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
历史上的今天:
2021-08-29 【模板】最小斯坦纳树
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
menu
点击右上角即可分享
微信分享提示