多项式基本操作

多项式求逆

给定一个 (n-1) 次的多项式 (A(x)(a_0 eq 0)) ,要求一个多项式 (F(x)) 满足 (F(x)A(x) equiv 1 pmod x^n)
假设求出了 (F_0(x)) 满足 (F_0(x)A(x) equiv 1 pmod{x^{lceil frac{n}{2} ceil}}) ,那么有

[egin{aligned} F_0(x)A(x) equiv F(x)A(x) equiv 1 pmod{x^{lceil frac{n}{2} ceil}} \A(x)(F(x)-F_0(x)) equiv 0 pmod{x^{lceil frac{n}{2} ceil}} end{aligned} ]

由于 (A(x) eq 0) ,所以

[egin{aligned} F(x)-F_0(x) equiv 0 pmod{x^{lceil frac{n}{2} ceil}} \(F(x)-F_0(x))^2 equiv 0 pmod{x^n} \F^2(x)-2F(x)F_0(x)+F_0^2(x) equiv 0 pmod{x^n} end{aligned} ]

又因为 (F(x)A(x) equiv 1 pmod{x^n}) ,两边都乘个 (A(x))

[F(x) equiv 2F_0(x)-A(x)F_0^2(x) pmod{x^n} \ equiv F_0(x)(2-A(x)F_0(x)) pmod{x^n} ]

所以我们可以递归求解,时间复杂度 (T(n) = T(n/2)+nlog n = nlog n)

void get_inv(int *a, int *f, int n){
	if(n == 1)return f[0] = fpow(a[0], mod-2), void();
	get_inv(a, f, n+1>>1), init(2*n-1);//init()处理数组长度和蝴蝶变换
	fp(i, 0, n-1)inv_ary[i] = a[i];
	ntt(f, 0), ntt(inv_ary, 0);
	fp(i, 0, lim-1)f[i] = 1ll*f[i]*(2-1ll*f[i]*inv_ary[i]%mod+mod)%mod;
	ntt(f, 1);
	fp(i, n, lim-1)f[i] = 0;
	fp(i, 0, lim-1)inv_ary[i] = 0;
}

多项式求 ( m{ln})

给定一个 (n-1) 次的多项式 (A(x)(a_0 = 1)) ,要求一个多项式 (F(x)) 满足 (F(x) equiv ln A(x) pmod{x^n})
两边求个导得到:

[F'(x) equiv frac{A'(x)}{A(x)} pmod{x^n} ]

所以只需要对 (A(x)) 求个导和逆就能求出 (F'(x)) 了。最后再对 (F'(x)) 求个积分,由于 (a_0=1) ,所以常数项为 (0) 。时间复杂度为 (mathcal{O} (nlog n))

void get_ln(int *a, int *f, int n){
	get_inv(a, ln_ary, n), init(2*n-2);
	fp(i, 1, n-1)f[i-1] = 1ll*a[i]*i%mod;
	ntt(f, 0), ntt(ln_ary, 0);
	fp(i, 0, lim-1)f[i] = 1ll*f[i]*ln_ary[i]%mod;
	ntt(f, 1);
	fp(i, n-1, lim)f[i] = 0;
	fp(i, 0, lim)ln_ary[i] = 0;
	fb(i, n-1, 1)f[i] = 1ll*f[i-1]*inv[i]%mod;
	f[0] = 0;
}

牛顿迭代

给定一个函数 (G(x)) ,要求一个多项式 (F(x)) 满足 (G(F(x)) equiv 0 pmod{x^n})
假设求出了 (F_0(x)) 满足 (G(F_0(x)) equiv 0 pmod{x^{lceil frac{n}{2} ceil}}) ,那么把 (G(x))(F_0(x)) 处泰勒展开可以得到:

[G(F(x)) equiv G(F_0(x))+G'(F_0(x))(F(x)-F_0(x))+frac{G''(F_0(x))}{2}(F(x)-F_0(x))^2+cdots pmod{x^n} \ equiv G(F_0(x))+G'(F_0(x))(F(x)-F_0(x)) equiv 0 pmod{x^n} \ F(x) equiv F_0(x)-frac{G(F_0(x)}{G'(F_0(x))} pmod{x^n} ]

因为 (F(x)-F_0(x)) 最低次是 (x^{lceil frac{n}{2} ceil}) ,所以从第三项开始模 (x^n) 就为 (0) 了。 注意这里的求导是求 (F_0(x)) 的偏导 。然后就可以递归计算了。


多项式 ( m{exp})

给定一个 (n-1) 次多项式 (A(x)(a_0=0)) ,要求一个多项式 (F(x)) 满足 (F(x) equiv e^{A(x)} pmod{x^n})
两边求个 (ln)(ln F(x) equiv A(x) pmod{x^n}) 。设 (G(F(x))=ln F(x)-A(x)) ,那就相当于求 (F(x)) 满足 (G(F(x)) equiv 0 pmod{x^n})
根据牛顿迭代的式子, (F(x) equiv F_0(x)-F_0(x)(ln F_0(x)-A(x)) equiv F_0(x)(1-ln F_0(x)+A(x))) 。递归求解即可,时间复杂度 (mathcal{O} (nlog n))

void get_exp(int *a, int *f, int n){
	if(n == 1)return f[0] = 1, void();
	get_exp(a, f, n+1>>1), get_ln(f, exp_ary, n), init(2*n-1);
	fp(i, 0, n-1)exp_ary[i] = (a[i]-exp_ary[i]+mod)%mod;
	if((++exp_ary[0]) ==  mod)exp_ary[0] = 0;
	ntt(f, 0), ntt(exp_ary, 0);
	fp(i, 0, lim-1)f[i] = 1ll*f[i]*exp_ary[i]%mod;
	ntt(f, 1);
	fp(i, n, lim-1)f[i] = 0;
	fp(i, 0, lim-1)exp_ary[i] = 0;
}

分治 ( m{FFT/NTT})

求出 (prod_{i=1}^n(a_{i,0}+a_{i,1}x+a_{i,2}x^2+ cdots +a_{i,k+1}x^{k+1})) ,要求复杂度为 (mathcal{O} (nk log^2 nk)) 。一般情况下 (k) 都等于 (1)
显然不能从左到右乘过去,这样的话复杂度高达 (mathcal{O} (n^2))
考虑分治,每次做完左右两边的乘法,这样左右两边的长度都是 (frac{len}{2}) 的, (len) 是当前的分治区间长度。然后把两边的乘起来即可。显然复杂度降到了 (mathcal{O} (nk log^2 nk)) 。当 (k=1) 时就是 (mathcal{O} (n log^2 n))
贴个 (k=1) 时的代码((a_0 = 1))。

int div_ary[20][maxn<<2];
void divntt(int d, int l, int r){
	if(l == r)return div_ary[d][0] = 1, div_ary[d][1] = mod-a[l], void();
	int md = l+r>>1, len = r-l+2;
	divntt(d, l, md), divntt(d+1, md+1, r), init(len), ntt(div_ary[d], 0), ntt(div_ary[d+1], 0);
	fp(i, 0, lim-1)div_ary[d][i] = 1ll*div_ary[d][i]*div_ary[d+1][i]%mod;
	ntt(div_ary[d], 1);
	fp(i, len, lim-1)div_ary[d][i] = 0;
	fp(i, 0, lim-1)div_ary[d+1][i] = 0;
}

常见的数

第一类斯特林数

定义(egin{bmatrix} n\m end{bmatrix}) 表示把 (n) 个有标号元素划分成 (m) 个圆排列的方案数。
递推公式

[egin{aligned} egin{bmatrix} n\m end{bmatrix} = egin{bmatrix} n-1\m-1 end{bmatrix}+(n-1)egin{bmatrix} n-1\m end{bmatrix} quad (n > 1) \egin{bmatrix} n\0 end{bmatrix} = [n=0] \egin{bmatrix} n\1 end{bmatrix} = (n-1)! quad (n geq 1) end{aligned} ]

考虑加入第 (n) 个元素,它要么新成一个环,要么排在前 (n-1) 个元素中某一个的后面。
组合意义(n! = sum_{i=0}^negin{bmatrix} n\i end{bmatrix})
可以理解为一个排列对应为若干个置换,每个置换又对应一个圆排列。
生成函数(sum_{i=0}^{infty} egin{bmatrix} n\i end{bmatrix}x^i=x^{overline{n}})
考虑归纳法,首先有 (egin{bmatrix} 0\0 end{bmatrix}x^0=x^{overline{0}})

[(x+n)x^{overline{n}} = x^{overline{n+1}} \(x+n)sum_{i=0}^{infty} egin{bmatrix} n\i end{bmatrix}x^i = n!x+sum_{i=2}^{infty}(egin{bmatrix} n-1\i-1 end{bmatrix}+egin{bmatrix} n-1\i end{bmatrix})x^i=sum_{i=0}^{infty} egin{bmatrix} n+1\i end{bmatrix}x^i ]

所以 (sum_{i=0}^{infty} egin{bmatrix} n+1\i end{bmatrix}x^i=x^{overline{n+1}})
考虑求这个生成函数。直接的方法可以用分治 ( m{NTT}) 求,复杂度 (mathcal{O} (nlog^2 n))。还有种倍增的方法。
(F_n(x) = x^{overline{n}}) ,考虑怎么通过它求出 (F_{2n}(x)) 。显然有 (F_{2n}=F_n(x)F_n(x+n))

[egin{aligned} F_n(x+n) = sum_{i=0}^{infty} egin{bmatrix} n\i end{bmatrix}(x+n)^i \=sum_{i=0}^n egin{bmatrix} n\i end{bmatrix}sum_{j=0}^i{ichoose j}n^{i-j}x^j \=sum_{j=0}^nx^jsum_{i=j}^n {i choose j}egin{bmatrix} n\i end{bmatrix}n^{i-j} \=sum_{j=0}^nfrac{x^j}{j!}sum_{i=j}^nfrac{i!}{(i-j)!}egin{bmatrix} n\i end{bmatrix}n^{i-j} end{aligned} ]

很容易看出来后面的式子可以卷积。设 (a_i=i!egin{bmatrix} n\i end{bmatrix},b_i=frac{n^i}{i!}),将 (a) 的下标反转一下,卷积的第 (n-j) 次项系数除以 (j!) 就是 (F_n(x+n)) 的第 (j) 次项系数。现在就可以递归求解了,当 (n) 为奇数时就将 (n) 减一,求出多项式后乘一个 (x+n-1) 即可。复杂度 (mathcal{O} (nlog n))


第二类斯特林数

定义(egin{Bmatrix} n\m end{Bmatrix}) 表示将 (n) 个有标号元素划分为 (m) 个无标号非空集的方案数。
递推公式

[egin{aligned} egin{Bmatrix} n\m end{Bmatrix} = egin{Bmatrix} n-1\m-1 end{Bmatrix}+megin{Bmatrix} n-1\m end{Bmatrix} \egin{Bmatrix} n\0 end{Bmatrix} = [n = 0] end{aligned} ]

考虑加入第 (n) 个元素,它要么新成一个集合,要么被划进已有的元素。
组合意义(m^n = sum_{i=0}^m{mchoose i}egin{Bmatrix} n\i end{Bmatrix}i!)
因为左边是 (n) 个有标号元素划分为任意个有标号集合的方案数,那么枚举有几个非空集,很自然能得到右边的式子。
通项公式

[egin{Bmatrix} n\m end{Bmatrix} = frac{1}{m!}sum_{i=0}^m(-1)^i{m choose i}(m-i)^n ]

有两种方法理解这个式子:
由于不能选空集,那就容斥掉空集的情况。所以枚举选了 (i) 个空集,然后将所有 (n) 个元素放入 (m-i) 个集合中(可以为空集)。容易看出来容斥系数为 ((-1)^i{mchoose i})
或者考虑二项式反演:

[m^n = sum_{i=0}^m{mchoose i}egin{Bmatrix} n\i end{Bmatrix}i! \egin{Bmatrix} n\m end{Bmatrix}m! = sum_{i=0}^m(-1)^i{m choose i}(m-i)^n ]

有了这个通项之后就可以 (mathcal{O} (nlog n)) 求解一行第二类斯特林数了,因为把组合数打开可以发现是卷积的形式。


贝尔数

定义(B_n) 表示将 (n) 个有标号元素划分为任意个无标号非空集合的方案数。
递推公式

[egin{aligned} B_{n+1} = sum_{i=0}^n{nchoose i}B_{n-i} \B_0 = 1 end{aligned} ]

考虑加入第 (n+1) 个元素,枚举它与多少个元素划进同一个集合,剩下的元素任意划分。
组合意义

[egin{aligned} B_n = sum_{i=0}^negin{Bmatrix} n \ i end{Bmatrix}=sum_{m=0}^nfrac{1}{m!}sum_{i=0}^m(-1)^{i}{mchoose i}(m-i)^n\ =sum_{m=0}^nsum_{i=0}^mfrac{(-1)^{i}}{i!} imes frac{(m-i)^n}{(m-i)!}\ =sum_{m=0}^nsum_{i=0}^mfrac{(-1)^{m-i}}{(m-i)!} imes frac{i^n}{i!}\ =sum_{i=0}^nfrac{i^n}{i!}sum_{m=i}^nfrac{(-1)^{m-i}}{(m-i)!}\ =sum_{i=0}^nfrac{i^n}{i!}sum_{m=0}^{n-i}frac{(-1)^m}{m!} end{aligned} ]

这样的话后面的 (sum) 就只与上界有关了,先给后面的 (sum) 求个前缀和,再线筛 (i^n) ,就可以 (mathcal{O}(n)) 求解一个贝尔数了。
生成函数(sum_{n=0}^{infty}B_nx^n = e^{e^x-1})
写出 (n) 个数划分成一个集合的方案数 (f_n) ,显然 (f_n=1) 。考虑划分成任意个集合的方案数就是 (e^{F(x)}) ,其中 (F(x) = sum_{n=1}^{infty}frac{f_n}{n!}x^n = e^x-1) 。所以写一个多项式 ( m{exp}) 就可以 (mathcal{O} (nlog n)) 求解前 (n) 个贝尔数了。
通项公式

[egin{aligned} e^{e^x-1} = frac{1}{e}e^{e^x}=frac{1}{e}sum_{n=0}^{infty}frac{(e^x)^n}{n!} \=frac{1}{e}sum_{n=0}^{infty}frac{1}{n!}sum_{i=0}^{infty}frac{(nx)^{i}}{i!} \=sum_{i=0}^{infty}frac{x^i}{i!} imes frac{1}{e}sum_{n=0}^{infty}frac{n^i}{n!} end{aligned} ]

所以通项为 (frac{1}{e}sum_{n=0}^{infty}frac{n^i}{n!})
( m Touchard) 同余
(B_{n+p}equiv B_n+B_{n+1}pmod{p})
引理 (1)(B_{n+m}=sum_{i=0}^nsum_{j=0}^m j^{n-i}egin{Bmatrix}m\jend{Bmatrix}{nchoose i}B_i)
把n+m个元素分成n个元素和m个元素。首先枚举m个元素划分成了j个集合,就有了(egin{Bmatrix}m\jend{Bmatrix});再枚举n个元素中选i个出来任意划分,就有了({nchoose i}B_i);再把剩下的n-i个元素随意放进m个元素的那j个集合里,就有了(j^{n-i}) 。根据乘法原理乘起来,就是(B_{n+m})。正确性是因为每种划分方案都可以像这样描述。
引理 (2)(egin{Bmatrix}n\mend{Bmatrix}equiv0pmod n(1<m<n),n)为质数 。
展开左边的式子:(egin{Bmatrix}n\mend{Bmatrix}=frac{1}{m!}sum_{i=0}^m(-1)^i{mchoose i}(m-i)^n),可以发现组合数的m!可以跟前面约了:

[=sum_{i=0}^mfrac{(-1)^i}{i!}frac{(m-i)^n}{(m-i)!} ]

根据费马小定理,可以把m-i的指数消一下:(equivsum_{i=0}^mfrac{(-1)^i}{i!}frac{m-i}{(m-i)!}pmod n)

[equivsum_{i=0}^mfrac{(-1)^i}{i!}frac{1}{(m-i-1)!}pmod n\ equivfrac{1}{(m-1)!}sum_{i=0}^m{m-1choose i}(-1)^ipmod n ]

(i=m)的时候后面就=0,所以(i)最多等于(m-1),那么根据二项式定理就可得:

[equiv[m-1=0]pmod n ]

所以当(1<m<n)的时候(egin{Bmatrix}n\mend{Bmatrix})就同余0。
证明 ( m Touchard) 同余:
最后我们写出引理1的式子:

[B_{n+p}=sum_{i=0}^nsum_{j=0}^p j^{n-i}egin{Bmatrix}p\jend{Bmatrix}{nchoose i}B_i \=sum_{j=0}^pegin{Bmatrix}p\jend{Bmatrix} sum_{i=0}^nj^{n-i}{nchoose i}B_i ]

根据引理(2),当(1<j<p)时,后边的式子值为(0)。又根据第二类斯特林数的定义,当(j=0)时,后边也为(0),当(j=1)或者(p)时,(egin{Bmatrix}p\jend{Bmatrix}=1),。所以这个式子可以进一步写成:

[egin{Bmatrix}p\1end{Bmatrix}sum_{i=0}^n{nchoose i}B_i+ egin{Bmatrix}p\pend{Bmatrix}sum_{i=0}^np^{n-i}{nchoose i}B_i \=sum_{i=0}^n{nchoose i}B_i+sum_{i=0}^np^{n-i}{nchoose i}B_i ]

根据最开始的(n^2)的递推式,加号左边的就是(B_{n+1});由于是模意义下的,所以当(i eq n)时,(p^{n-i}{nchoose i}B_iequiv 0pmod{p})。。当i=n时,这个式子等于(B_n)
所以(B_{n+p}equiv B_n+B_{n+1}pmod{p})


划分数

定义(p_{n,m}) 表示将 (n) 划分成 (m) 个无标号 自然数 和的方案数。
递推公式(p_{n,m} = p_{n-m,m}+p_{n,m-1})
要么给已有的 (m) 个数都加 (1) ,要么加入一个 (0)
生成函数(P_n(x) = sum_{i=0}^{infty}p_{i,n}x^i)
根据递推公式,

[P_n(x) = sum_{i=n}^{infty}(p_{i-n,n}+p_{i,n-1})x^i=x^nP_n(x)+P_{n-1}(x) \P_n(x) = frac{P_{n-1}(x)}{1-x^n} ]

又有 (P_1(x) = sum_{i=0}^{infty}x^i=frac{1}{1-x}) ,不难发现

[P_n(x) = prod_{i=1}^nfrac{1}{1-x^i} ]

直接的方法就是分治 ( m NTT) ,复杂度 (mathcal{O} (nlog^2 n))
观察到 (x^i) 的系数都是 (-1) ,考虑继续优化:

[ln P_n(x) = -sum_{i=1}^nln(1-x^i) ]

(F_i(x) = ln(1-x^i))

[F_i'(x) = -frac{ix^{i-1}}{1-x^i} = (-ix^{i-1})sum_{j=0}^{infty}x^{ij} \F_i'(x) = -sum_{j=0}^{infty}ix^{i(j+1)-1}=-sum_{j=1}^{infty}ix^{ij-1} \F_i(x) = -sum_{j=1}^{infty}frac{x^{ij}}{j} ]

所以暴力确定 (ln P_n(x)) 的系数是 (mathcal{O} (nln n)) 的,再做个 ( m exp) 就可以求得 (P_n(x))


一些奇技淫巧

( m EularTransform)

给定长度为 (n) 的数列 (a) ,要求 (F(x) = sum_{i=1}^nfrac{1}{1-a_ix})
当然可以通分+分治 ( m NTT) ,但那样常数有点大。
( m EularTransform) 的思想是通过 (1-x(ln (1-a_ix))' = 1+frac{a_i}{1-a_ix}=frac{1}{1-a_ix}) ,得到

[F(x) = n-xsum_{i=1}^n(ln(1-a_ix))'=n-x(ln prod_{i=1}^n(1-a_ix))' ]

(prod) 就用分治 ( m NTT) 算,复杂度 (mathcal{O} (nlog^2 n))

不知道叫啥

给定长度为 (n) 的数列 (a) 和多项式 (F(x)) ,要求 (sum_{i=1}^nF(a_ix))
暴力做显然是 (mathcal{O} (n^2)) 的。
注意到最后的多项式的第 (m) 次项系数肯定是 (sum_{i=1}^na_i^m) 。考虑写出这玩意儿的 ( m OGF)

[G(x) = sum_{m=0}^{infty}(sum_{i=1}^na_i^m)x^m= sum_{i=1}^nsum_{m=0}^{infty}(a_ix)^m= sum_{i=1}^nfrac{1}{1-a_ix} ]

剩下的就是上面的 ( m EularTransform) 了。

自然数幂和

对于所有 (nin [0,N]) 求出 (sum_{i=0}^mi^n) ,也就是刚才那个东西的特殊形式。
这次我们写出 ( m EGF)

[F(x) = sum_{n=0}^{infty}(sum_{i=0}^mi^n)frac{x^n}{n!}=sum_{i=0}^msum_{n=0}^{infty}frac{(ix)^n}{n!}=sum_{i=0}^me^{ix}=frac{e^{(m+1)x}-1}{e^x-1} ]

给分母展开求个逆再乘上分母即可。注意到分母的常数项为 (0) 不能直接求逆,但是分子的常数项也为 (0) ,同时除以 (x) 即可。复杂度 (mathcal{O} (nlog n))

任意模数 ( m NTT)

(A(x)B(x)) 的系数对(10^9+7) 取模的结果,最高次项是 (10^5) 级别,系数是 (10^9) 级别。
分析可得最后系数的值域应是 (10^23) 以内。那么对 (998244353,1004535809,469762049) 三个模数分别做 ( m NTT) ,就能用 ( m CRT) 解出真实值(因为三个模数乘起来大于 (10^23) ),再对 (10^9+7) 取模即可。选这三个因为原根都是 (3)


咕咕咕

原文地址:https://www.cnblogs.com/akura/p/14594580.html