形式冪級數 [學習筆記]


形式冪級數

沉迷多項式,無法自拔...

不具體寫了看筆記本,這里稍微記一下。

目錄

  1. 多項式的各種運算
  2. 伯努利數
  3. 拉格朗日反演

任意模數卷積

我的三模數ntt跑得好慢,然后拆系數fft跑的好快

\(M = \lceil P \rceil\),將整數表示成\(k\cdot M+b\)的形式

\(x\)\(y\)進行卷積,分別表示稱\(a\cdot M + b,\ c\cdot M + d\)

\[(a\cdot M + b)\cdot (c\cdot M + d) = ac M^2 + (ad+bc)M + bd \]

\(a,b,c,d\)進行dft和idft即可

每個數大小在\(10^{14}\)級別,可以使用復數下fft,共進行7次運算

通常M取\(32768=2^{15}\)

根據猜測,系數表示不溢出double點值表示就不會溢出double。這玩意應該只能承受一次點值乘法

	void mul_any(int *x, int *y, int lim) {
		for(int i=0; i<lim; i++) {
			a[i].x = x[i] >> 15; b[i].x = x[i] & 32767;
			c[i].x = y[i] >> 15; d[i].x = y[i] & 32767;
		}
		dft(a, 1); dft(b, 1); dft(c, 1); dft(d, 1);
		for(int i=0; i<n; i++) {
			cd _a = a[i], _b = b[i], _c = c[i], _d = d[i];
			a[i] = _a * _c;
			b[i] = _a * _d + _b * _c;
			c[i] = _b * _d;
		}
		dft(a, -1); dft(b, -1); dft(c, -1);
		for(int i=0; i<lim; i++) {
			ll _a = (ll) floor(a[i].x + 0.5) %mo, _b = (ll) floor(b[i].x + 0.5) %mo, _c = (ll) floor(c[i].x + 0.5) %mo;
			printf("%lld ", ((_a << 30) %mo + (_b << 15) %mo + _c) %mo);
		}
	}


以下復雜度均為\(T(n) = T(n/2) + O(nlogn) =O(nlogn)\)

模板在最下方


多項式求逆元

\[A(x) * B(x) \equiv 1 \pmod {x^n} \]

  • 注意到這時候\(A(x)*B(x)\)\(1...n-1\)次項系數為0

用倍增的思想,已知\(\mod x^{\lceil \frac{l}{2} \rceil}\)的逆元\(B_0(x)\)\(\mod x^l\)下的逆元\(B(x)\)

\(l=1\)時,\(b_0 = a_0^{-1}\),可以發現多項式有逆的充要條件是常數項有逆

兩式相減,然后平方,同乘\(A(x)\),得到

\[B(x) \equiv B_0(x) * (2 - A(x) * B_0(x)) \pmod {x^l} \]

處理\(\mod x^l\)時,\(l\)就是當前的次數界,次數\(\ge l\)的都整除沒了。

可以理解為只關心前l項



多項式開根

\[B^2(x) \equiv A(x) \pmod {x^n} \]

同樣倍增的思想

已知\(\mod x^{\lceil \frac{l}{2} \rceil}\)的平方根\(B_0(x)\)\(\mod x^l\)下的平方根\(B(x)\)

\(l=1\)時,\(b_0 \equiv \sqrt{a_0} \pmod x\),可能需要二次剩余

移項化簡后得到

\[B(x) \equiv 2^{-1}\cdot (B_0(x) + A(x) * B_0^{-1}(x)) \pmod{x^n} \]

同時還需要求逆...



牛頓迭代法

給出\(G(x)\),求\(F(x)\)

\[G(F(x)) \equiv 0 \pmod{x^n} \]

倍增的思想。將\(G(F(X))\)\(F_0(x)\)處泰勒展開得到

\[F(x) \equiv F_0(x) - \frac{G(F_0(x))}{G'(F_0(x))} \pmod{x^l} \]

也可以用這個式子求逆元和開根,最后的結果式子一樣。


  • 多項式求ln和exp就是和對應的麥克勞林級數復合,所以要求常數項為0


多項式求ln

給出\(F(x) = 1 + \sum_{i \ge 1}f_ix^i\)

求一下導

\[\ln F(x) = \int \frac{F'(x)}{F(x)}dx \]



多項式求exp

給出\(A(x) = \sum_{i \ge 1}a_ix^i\)

\[e^{A(x)} - B(x) \equiv 0 \pmod {x^n} \]

取對數后使用牛頓迭代法

\[B(x) = B_0(x)(1 - \ln B_0(x) + A(x)) \]



多項式k次冪

\(A(x)\)的常數項為1

\[A(x)^k = exp(k \ln A(x)) \]

否則提取最低次項\(ax^d\)

\[A(x)^k = (ax^d)^k (\frac{A(x)}{ax^d})^k \]



伯努利數

wiki

用來解決等冪求和問題

\[\begin{align} \sum_{i=0}^{n-1} i^m = \frac{1}{m+1}\sum_{i=0}^m \binom{m+1}{i}B_i^- n^{m+1-i} \\ S_m(n) = \sum_{i=1}^{n} i^m = \frac{1}{m+1}\sum_{i=0}^m \binom{m+1}{i}B_i^+ n^{m+1-i} \\ \end{align} \]

復雜度與冪次有關

除了\(B_1\),其他奇數項都是0。\(B_1^+ = \frac{1}{2},B_1^-=-\frac{1}{2}\)

\(0^0=1\)

遞推關系

\(n=1, m\neq 0\),

\[\sum_{i=0}^m \binom{m+1}{i}B_i^- = 0,\ B_0=1, B_1^-=-\frac{1}{2} \]

指數型生成函數

對於\(B^-\),

\[\sum_{i=0}^\infty B_i\frac{x^i}{i!} =\frac{x}{e^x - 1} = (\sum_{i=0}^\infty \frac{x^i}{(i+1)!})^{-1} \]

使用多項式求逆元即可預處理伯努利數. 求\(\mod x^{n+1}\)意義下逆元


預處理任意模數伯努利數的模板



拉格朗日反演

復合逆(反函數):

沒有常數項的\(f(x), g(x)\)\(f(g(x))=x\),那么互為復合逆,\(f_1g_1=1,g(f(x))=x\)

用拉格朗日反演可以\(O(nlogn)\)復合逆某一項的系數

\[[x^n]g(x) = \frac{1}{n}[\omega^{n-1}](\frac{\omega}{f(\omega)})^n \]

可以配合多項式k次冪使用。

生成函數中出現x之后可以用啦。



模板

namespace ntt {
	int g = 3, rev[N];
	void dft(int *a, int n, int flag) {
		int k = 0; while((1<<k) < n) k++;
		for(int i=0; i<n; i++) {
			rev[i] = (rev[i>>1]>>1) | ((i&1)<<(k-1));
			if(i < rev[i]) swap(a[i], a[rev[i]]);
		}
		for(int l=2; l<=n; l<<=1) {
			int m = l>>1, wn = Pow(g, flag == 1 ? (P-1)/l : P-1-(P-1)/l);
			for(int *p = a; p != a+n; p += l)
				for(int k=0, w=1; k<m; k++, w = (ll)w*wn %P) {
					int t = (ll) w * p[k+m] %P, r = p[k];
					p[k+m] = (r - t + P) %P;
					p[k] = (r + t) %P;
				}
		}
		if(flag == -1) {
			ll inv = Pow(n, P-2);
			for(int i=0; i<n; i++) a[i] = a[i] * inv %P;
		}
	}
	
	void inverse(int *a, int *b, int l) {
		static int t[N];
		if(l == 1) {b[0] = Pow(a[0], P-2); return;}
		inverse(a, b, l>>1);
		int n = l<<1;
		for(int i=0; i<l; i++) t[i] = a[i], t[i+l] = 0;
		dft(t, n, 1); dft(b, n, 1);
		for(int i=0; i<n; i++) b[i] = (ll) b[i] * (2 - (ll) t[i] * b[i] %P + P) %P;
		dft(b, n, -1); for(int i=l; i<n; i++) b[i] = 0;
	}

	void sqrt(int *a, int *b, int l) {
		static int t[N], ib[N];
		if(l == 1) {b[0] = 1; return;}
		sqrt(a, b, l>>1);
		int n = l<<1;
		for(int i=0; i<l; i++) t[i] = a[i], t[i+l] = 0, ib[i] = ib[i+l] = 0;
		inverse(b, ib, l);
		dft(t, n, 1); dft(b, n, 1); dft(ib, n, 1);
		for(int i=0; i<n; i++) b[i] = (ll) inv2 * (b[i] + (ll) t[i] * ib[i] %P) %P;
		dft(b, n, -1); for(int i=l; i<n; i++) b[i] = 0;
	}

	void ln(int *a, int *b, int l) {
		static int da[N], ia[N];
		int n = l<<1;
		for(int i=0; i<n; i++) da[i] = ia[i] = 0;
		for(int i=0; i<l-1; i++) da[i] = (ll) (i+1) * a[i+1] %P;
		inverse(a, ia, l);
		dft(da, n, 1); dft(ia, n, 1);
		for(int i=0; i<n; i++) b[i] = (ll) da[i] * ia[i] %P;
		dft(b, n, -1);
		for(int i=l-1; i>0; i--) b[i] = (ll) inv[i] * b[i-1] %P; b[0] = 0;
		for(int i=l; i<n; i++) b[i] = 0;
	}
	
	void exp(int *a, int *b, int l) {
		static int t[N];
		if(l == 1) {b[0] = 1; return;}
		exp(a, b, l>>1);
		int n = l<<1;
		for(int i=0; i<n; i++) t[i] = 0;
		ln(b, t, l);
		for(int i=0; i<l; i++) t[i] = (a[i] - t[i] + P) %P; t[0] = (t[0] + 1) %P;
		dft(b, n, 1); dft(t, n, 1);
		for(int i=0; i<n; i++) b[i] = (ll) b[i] * t[i] %P;
		dft(b, n, -1); for(int i=l; i<n; i++) b[i] = 0;
	}

	void power(int *a, int k, int l) {
		static int t[N];
		int n = l<<1;
		for(int i=0; i<n; i++) t[i] = 0;
		ln(a, t, l);
		for(int i=0; i<l; i++) t[i] = (ll) k * t[i] %P;
		for(int i=0; i<n; i++) a[i] = 0;
		exp(t, a, l);
	}
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM