zoukankan      html  css  js  c++  java
  • 多项式全家桶

    多项式乘法

    (FFT Rightarrow) 传送门

    (NTT Rightarrow) 传送门

    (FFT)

    void FFT(int lim, Complex *a, int op) {
    	for (int i = 0; i < lim; ++i)
    		if (i < r[i]) swap(a[i], a[r[i]]);
    	for (int len = 2; len <= lim; len <<= 1) {
    		int mid = len >> 1;
    		Complex Wn = {cos(Pi / mid), op * sin(Pi / mid)};
    		for (int i = 0; i < lim; i += len) {
    			Complex w = {1, 0};
    			for (int j = 0; j < mid; ++j, w = w * Wn) {
    				Complex x = a[i + j], y = w * a[i + j + mid];
    				a[i + j] = x + y;
    				a[i + j + mid] = x - y;
    			}
    		}
    	}
    }
    

    (NTT)

    ll root(const ll p) {
    	for (int i = 2; i <= p; ++i) {
    		int x = p - 1;
    		bool flag = true;
    		for (int k = 2; k * k <= p - 1; ++k) if (!(x % k)) {
    			if (ksm(i, (p - 1) / k) == 1) {
    				flag = false;
    				break;
    			}
    			while (!(x % k)) x /= k;
    		}
    		if (flag && (x == 1 || ksm(i, (p - 1) / x) != 1)) return i;
    	}
    }
    void NTT(int lim, ll *a, int op) {
    	for (int i = 0; i < lim; ++i)
    		if (i < r[i]) swap(a[i], a[r[i]]);
    	for (int len = 2; len <= lim; len <<= 1) {
    		int mid = len >> 1;
    		ll Wn = ksm(op == 1 ? G : Gx, (mod - 1) / len);
    		for (int i = 0; i < lim; i += len) {
    			ll w = 1;
    			for (int j = 0; j < mid; ++j, w = (w * Wn) % mod) {
    				ll x = a[i + j], y = w * a[i + j + mid] % mod;
    				a[i + j] = (x + y) % mod;
    				a[i + j + mid] = (x - y + mod) % mod;
    			}
    		}
    	}
    }
    

    多项式求逆

    当多项式只有一项时,那么显然 (G_0) 就是 (F_0) 的逆元。

    考虑一般情况下,如果我们已知 (F(x) H(x) equiv 1 (mod x^{lceil frac{n}{2} ceil})) ,如何求出 (F(X)G(x) equiv 1(mod x^n))

    已知 (F(x) H(x) equiv 1 (mod x^{lceil frac{n}{2} ceil}))

    又显然 (F(X)G(x) equiv 1(mod x^{lceil frac{n}{2} ceil}))

    (x ^ n) 相当于将次数大于等于 (n) 的项舍去了,模 (x^{lceil frac{n}{2} ceil}) 则相当于舍去了更多的项,所以前者满足,后者一定满足。

    将两个式子相减 (F(x)left[ G(x) - H(x) ight] equiv 0 (mod x ^ {lceil frac{n}{2} ceil}))

    (G(x) - H(x) equiv 0 (mod x ^ {lceil frac{n}{2} ceil}))

    然后将两边·平方一下

    [G^2(x) - 2G(x)H(x)+ H^2(x) equiv 0 (mod x^{lceil frac{n}{2} ceil}) ]

    由于 (G(x)-H(x)) 在 模 (x^{lceil frac{n}{2} ceil}) 下为 (0),所以这个式子的结果的 (0)(lceil frac{n}{2} ceil - 1) 次项系数都为 (0)

    而平方之后,对于结果的 (i) 次项((0 le i le 2 imes lceil frac{n}{2} ceil - 1)),其系数 (a_i=sum limits_{j=0}^{i} a_j a_{i-j}), 其中 (a_j)(a_{i-j}) 必定至少有一项小于等于 (lceil frac{n}{2} ceil - 1),所以可以得知,平方之后的式子在模 (x^n) 意义下也为 (0)

    [G^2(x) - 2G(x)H(x)+ H^2(x) equiv 0 (mod x^{n}) ]

    给式子乘上一个 (F(x)),得到

    [F(x)G^2(x) - 2F(x)G(x)H(x)+ F(x)H^2(x) equiv 0 (mod x^{n}) ]

    由多项式乘法逆的定义 (F(x)G(x)equiv 0(mod x ^n))可以得到

    [G(x) - 2H(x)+ F(x)H^2(x) equiv 0 (mod x^{n}) ]

    再移项

    [G(x) equiv 2H(x)+ F(x)H^2(x) (mod x^{n}) ]

    于是就可以不断倍增,求出多项式乘法逆。

    void polyinv(int len, int *A, int * B) {
    	if (len == 1) {
    		B[0] = fpow(A[0], P - 2);
    		return;
    	}
    	static int tmp[_];
    	polyinv((len + 1) >> 1, A, B);
    	int lim = 1, k = 0;
    	while (lim < (len << 1)) lim <<= 1, ++k;
    	for (int i = 0; i < lim; ++i) r[i] = (r[i >> 1] >> 1) | ((i & 1) << (k - 1));
    	copy(A, A + len, tmp);
    	fill(tmp + len, tmp + lim, 0);
    	NTT(lim, tmp, 1);
    	NTT(lim, B, 1);
    	for (int i = 0; i < lim; ++i)
    		B[i] = (2ll - 1ll * B[i] * tmp[i] % P + P) * B[i] % P;
    	NTT(lim, B, -1);
    	fill(B + len, B + lim, 0);
    }
    

    多项式除法

    给定一个 (n) 次多项式 (F(x)) 和一个 (m) 次多项式 (G(x)) ,求出多项式 (Q(x)), (R(x)),满足:

    • (Q(x)) 次数为 (n-m)(R(x)) 次数小于 (m)
    • (F(x) = Q(x) * G(x) + R(x))

    首先考虑一种操作 (R) ,使得

    [A^R(x) = x^n A(frac{1}{x}) ]

    这个操作实际上是将 (A(x)) 的系数反转。

    接下来,考虑将 (F(x) = Q(x) * G(x) + R(x)) 中的 (x) 全部用 (frac{1}{x}) 替代,然后等式两边同时乘上 (x ^ n),得到

    [x^n F(frac{1}{x}) = x^n Q(x) * G(x) + x^n R(x) \ x^n F(frac{1}{x}) = x^{n-m} Q(x) * x^m G(x) + x^{n-m+1} x^{m-1} R(x) ]

    [F^R(x) = Q^R(x) G^R(x) + x^{n-m+1} R^R(x) ]

    比较难搞的是 (R(x)),考虑怎么消掉它。

    仔细观察一下,可以发现,(Q(x)) 反转后次数不会高于 (n-m),而 (x^{n-m+1} R^R(x)) 的最低次项次数高于 (n-m),因此,将上面的式子放到模 (x^{n-m+1}) 意义下,(R(x)) 就被消掉了。而由于 (F(x),G(x)) 是已知的元素,因此不会有任何问题。

    所以

    [F^R(x) = Q^R(x) G^R(x) (mod x^{n-m+1}) ]

    [Q^R(x) equiv F^R(x)G^R(x)^{-1} (mod x^{n-m+1}) ]

    系数反转可以直接 ( ext{reverse}) 实现,只要求出 (G^R(x)), 就可以得到 (Q^R(x)),然后反转回来回代,就得到了 (R(x))。时间复杂度 (O(Nlog N))

    多项式开方

    已知 (F(x)) ,求 (G(x)) 使得 (G^2equiv Fpmod{x^n})

  • 相关阅读:
    文本数据清洗总结
    PyTorch
    PyTorch
    NLP
    TF
    TF
    TF
    cairosvg
    word2vec 实现 影评情感分析
    Gensim
  • 原文地址:https://www.cnblogs.com/newbielyx/p/12219190.html
Copyright © 2011-2022 走看看