zoukankan      html  css  js  c++  java
  • 多项式开方

    [egin{align} A(x) &equiv B'(x)^2 &mod x^{n/2}\ A(x) &equiv B(x)^2 &mod x^{n}\ A(x) &equiv B(x)^2 &mod x^{n/2}\ B(x)^2 - B'(x)^2 &equiv 0 &mod x^{n/2}\ B^4(x)+B'(x)^4-2B(x)^2B'(x)^2 &equiv 0 &mod x^n\ B^4(x)+B'(x)^4 + 2B(x)^2B'(x)^2 &equiv 4B(x)^2B'(x)^2 &mod x^n\ B^2(x)+B'(x)^2 &equiv 2B(x)B'(x) &mod x^n\ A(x)+B'(x)^2 &equiv 2B(x)B'(x) &mod x^n\ B(x) &equiv dfrac{A(x)+B'(x)^2}{2B'(x)} &mod x^n end{align} ]

    跟求逆用的那种倍增方法极度相似。

    就是要用 O(n log2 n) 的时间来求了。真的要学牛顿迭代了吗(

    但是这个好像可以在倍增的过程中维护 B 的逆, 有点可以, 可以单 log, 以后再补。

    #include<bits/stdc++.h>
    typedef long long LL;
    using namespace std;
    
    const int N = 4e5 + 233, mo = 998244353;
    LL ksm(LL a, LL b) {
    	LL res = 1ll;
    	for(; b; b >>= 1, a = a * a % mo)
    		if(b & 1) res = res * a % mo;
    	return res;
    }
    const LL g = 3, ig = ksm(g, mo - 2), inv_2 = ksm(2, mo - 2);
    
    int rv[N];
    void NTT(LL *a, int n, int type) {
    	for(int i = 0; i < n; ++i) if(i < rv[i]) swap(a[i], a[rv[i]]);
    	for(int m = 2; m <= n; m = m << 1) {
    		LL w = ksm(type == 1 ? g : ig, (mo - 1) / m);
    		for(int i = 0; i < n; i += m) {
    			LL tmp = 1ll;
    			for(int j = 0; j < (m >> 1); ++j) {
    				LL p = a[i + j], q = tmp * a[i + j + (m >> 1)] % mo;
    				a[i + j] = (p + q) % mo, a[i + j + (m >> 1)] = (p - q + mo) % mo;
    				tmp = tmp * w % mo;
    			}
    		}
    	}
    	if(type == -1) {
    		LL Inv = ksm(n, mo - 2);
    		for(int i = 0; i < n; ++i) a[i] = a[i] * Inv % mo;
    	}
    }
    
    LL t[N];
    void poly_inv(int deg, LL *a, LL *b) {
    	if(deg == 1) { b[0] = ksm(a[0], mo - 2); return; }
    	poly_inv((deg + 1) >> 1, a, b);
    	int len = 1; while(len < (deg << 1)) len = len << 1;
    	for(int i = 0; i < deg; ++i) t[i] = a[i];
    	for(int i = deg; i < len; ++i) b[i] = t[i] = 0ll;
    	for(int i = 1; i < len; ++i) rv[i] = (rv[i>>1]>>1) | (i&1?len>>1:0);
    	NTT(b, len, 1), NTT(t, len, 1);
    	for(int i = 0; i < len; ++i) b[i] = b[i] * (2ll - t[i] * b[i] % mo) % mo;
    	NTT(b, len, -1);
    	for(int i = deg; i < len; ++i) b[i] = 0ll;
    }
    
    LL binv[N], c[N];
    void poly_sqrt(int deg, LL *a, LL *b) {
    	if(deg == 1) { b[0] = 1ll; return; }
    	poly_sqrt((deg + 1) >> 1, a, b);
    	for(int i = 0; i < deg; ++i) c[i] = 2ll * b[i] % mo;
    	poly_inv(deg, c, binv);
    	int len = 1; while(len < (deg << 1)) len = len << 1;
    	for(int i = 1; i < len; ++i) rv[i] = (rv[i>>1]>>1) | (i&1?len>>1:0);
    	for(int i = 0; i < deg; ++i) c[i] = a[i];
    	for(int i = deg; i < len; ++i) b[i] = binv[i] = c[i] = 0ll;
    	NTT(b, len, 1), NTT(binv, len, 1), NTT(c, len, 1);
    	for(int i = 0; i < len; ++i) b[i] = (c[i] + b[i] * b[i] % mo ) % mo * binv[i] % mo;
    	NTT(b, len, -1);
    	for(int i = deg; i < len; ++i) b[i] = 0ll;
    }
    
    int n;
    LL a[N], b[N];
    int main() {
    	scanf("%d", &n);
    	for(int i = 0; i < n; ++i) scanf("%lld", &a[i]);
    	poly_sqrt(n, a, b);
    	for(int i = 0; i < n; ++i) cout << (b[i]%mo + mo) % mo << ' ';
    	return 0;
    }
    
  • 相关阅读:
    移植spdylay到libcurl
    用到的C++标准库
    libcurl底层调用逻辑
    socket编程
    linux的一些机制Signal, Fork,
    openssl 编程
    对称加密,非对称加密
    ajax提交整个form表单
    一道基础的for语句js编译过程
    怎样将浏览器一句话变为文本编辑器
  • 原文地址:https://www.cnblogs.com/tztqwq/p/14335243.html
Copyright © 2011-2022 走看看