• 【LOJ】#150. 挑战多项式


    原题链接
    多项式全家桶!快乐!(好像少个除法,不过有除法好像不太快乐)
    (说真的这是我第一次写exp和开根。。。水平不行。。

    从最基础要实现的操作开始吧。。

    多项式取模(x^n)

    这个。。很简单了,把大于等于n指数的系数全改成0就好了

    多项式加减法

    按位加/减,复杂度(O(n))

    多项式求导数

    这个的话,选修2-1了解一下?

    ((ax^{n})’ = anx^{n - 1})

    多项式求积分

    同上

    我们只要求一个多项式的导数是该多项式即可

    列个方程可以发现

    (int ax^{n} = frac{a}{n + 1}x^{n + 1})

    多项式乘法

    FFT了解一下??不过这题是NTT,复杂度(O(n log n))

    多项式求逆元

    也就是(A(x)B(x) equiv 1 pmod{x^{2^{t}}})
    我们倍增一下,当(t = 0)的时候直接求(frac{1}{A(0)})
    如果不是的话有
    (B(x) equiv G(x) pmod{x^{2^{t}}})
    我们把(G(x))移过去

    (B(x) - G(x) equiv 0 pmod {x^{2^{t}}})

    两边平方一下

    ((B(x) - G(x))^{2} equiv 0 pmod {x^{2^{t + 1}}})

    (B(x)^{2} - 2B(x)G(x) + G(x)^{2} equiv 0 pmod {x^{2^{t + 1}}})

    (B(x)^{2} equiv 2B(x)G(x) - G(x)^{2} pmod {x^{2^{t + 1}}})

    两边同乘一个(A(x))

    (B(x) equiv 2G(x) - A(x)G(x)^{2} pmod {x^{2^{t + 1}}})

    就可以算了

    多项式开根

    和上面的构造很类似!

    (B(x)^2 = A(x) pmod{x^{2^{t}}})

    (t = 0),我们求(sqrt{A(0)}),这个可以写cipolla

    然后有

    (B(x) equiv G(x) pmod{x^{2^{t}}})

    (B(x) - G(x) equiv 0 pmod{x^{2^{t}}})

    再平方

    (B(x)^{2} - 2B(x)G(x) + G(x)^2 equiv 0 pmod{x^{2^{t + 1}}})

    然后把(B(x)^2)换成(A(x))

    (A(x)- 2B(x)G(x) + G(x)^2 equiv 0 pmod{x^{2^{t + 1}}})

    整理一下

    (B(x) equiv frac{A(x) + G(x)^2}{2G(x)} pmod{x^{2^{t + 1}}})

    多项式求ln

    (ln F(x) = G(x))

    两边分别求导

    (frac{F'(x)}{F(x)} = G'(x))

    然后再两边一起积分

    (int frac{F'(x)}{F(x)} = G(x))

    所以多项式求ln只要求个导数,求个逆元,求个积分就好了

    多项式求exp

    根据牛顿迭代我们有。。

    如果有个函数

    (B(A_t(x)) equiv 0 pmod{x^{2^{t}}})

    (A_{t + 1}(x) = A_{t}(x) - frac{B(A_t(x))}{B'(A_t(x))})

    注意下面求导的主元是(A_t(x))而不是(x)

    这个可以用泰勒展开展开证一下。。

    (B(A_{t + 1}(x)) equiv 0 pmod{x^{2^{t + 1}}})

    (0 = B(A_{t + 1}(x)) = B(A_t(x)) + frac{B'(A_t(x))(A_{t + 1}(x) - A_{t}(x))}{1!} + frac{B''(A_t(x))(A_{t + 1}(x) - A_t(x))^2}{2!}cdots)

    自第三项及以后,最低项就是(x^{2^{t + 1}})

    所以可以化简成

    (0 = B(A_t(x)) + B'(A_{t}(x))(A_{t + 1}(x) - A_t(x)))

    然后就可以得到

    (A_{t + 1}(x) = A_t(x) - frac{B(A_t(x))}{B'(A_{t}(x))})

    然后……

    (e^{F(x)} equiv G_{t}(x) pmod{x^{2^{t}}})

    然后同时取(ln)

    (F(x) - ln G_t(x) equiv 0 pmod {x^{2^{t}}})

    然后就是刚刚那个式子咯。。

    (G_{t + 1}(x) equiv G_{t}(x) - frac{F(x) - ln(G(x))}{-frac{1}{G(x)}}pmod{x^{2^{t + 1}}})

    还是刚刚那句话。。主元是(G_t(x))不是(x),所以(F(x))相当于一个常数项。。

    (G_{t + 1}(x) equiv G_{t}(x) + G_t(x)(F(x) - ln(G(x))) pmod {x^{2^{t + 1}}})

    然后就可以做了

    多项式快速幂

    (A^{k}(x) = e^{k ln A(x)})

    写的话有个小细节。。就是注意运算的时候指数取模不是对N取模,是对(2^t)取模。。

    #include <bits/stdc++.h>
    #define fi first
    #define se second
    #define pii pair<int,int>
    #define mp make_pair
    #define pb push_back
    #define space putchar(' ')
    #define enter putchar('
    ')
    #define MAXN 20000005
    #define eps 1e-10
    //#define ivorysi
    using namespace std;
    typedef long long int64;
    typedef unsigned int u32;
    typedef double db;
    template<class T>
    void read(T &res) {
    	res = 0;T f = 1;char c = getchar();
    	while(c < '0' || c > '9') {
    		if(c == '-') f = -1;
    		c = getchar();
    	}
    	while(c >= '0' && c <= '9') {
    		res = res * 10 + c - '0';
    		c = getchar();
    	}
    	res *= f;
    }
    template<class T>
    void out(T x) {
    	if(x < 0) {x = -x;putchar('-');}
    	if(x >= 10) {
    		out(x / 10);
    	}
    	putchar('0' + x % 10);
    }
    const int MOD = 998244353,MAXL = (1 << 21);
    int W[MAXL + 5],N,K,Inv[MAXL + 5];
    int inc(int a,int b) {
    	return a + b >= MOD ? a + b - MOD : a + b;
    }
    int mul(int a,int b) {
    	return 1LL * a * b % MOD;
    }
    int fpow(int x,int c) {
    	int res = 1,t = x;
    	while(c) {
    		if(c & 1) res = mul(res,t);
    		t = mul(t,t);
    		c >>= 1;
    	}
    	return res;
    }
    namespace Cipolla {
        int a,s;
        struct Complex {
            int r,i;
            Complex(int _x = 0,int _y = 0) {r = _x;i = _y;}
            friend Complex operator + (const Complex &a,const Complex &b) {
                return Complex(inc(a.r,b.r),inc(a.i,b.i));
            }
            friend Complex operator - (const Complex &a,const Complex &b) {
                return Complex(inc(a.r,MOD - b.r),inc(a.i,MOD - b.i));
            }
            friend Complex operator * (const Complex &a,const Complex &b) {
                return Complex(inc(mul(a.r,b.r),mul(mul(a.i,b.i),s)),inc(mul(a.r,b.i),mul(a.i,b.r)));
            }
        };
        u32 Rand() {
            static u32 x = 20020421;
            return x += x << 2 | 1;
        }
        Complex Fpow(Complex x,int c) {
            Complex res(1,0),t = x;
            while(c) {
                if(c & 1) res = res * t;
                t = t * t;
                c >>= 1;
            }
            return res;
        }
        int Sqrt(int N) {
            while(1) {
                a = Rand() % MOD;
                s = inc(mul(a,a),MOD - N);
                if(fpow(s,(MOD - 1) / 2) == MOD - 1) break;
            }
            Complex res(a,1);
            res = Fpow(res,(MOD + 1) / 2);
            if(res.r > MOD - res.r) res = MOD - res.r;
            return res.r;
         }
    };
    struct Poly {
    	vector<int> v;
    	Poly() {v.clear();}
    	Poly(int a) {v.clear();v.pb(a);}
    	Poly limit(int len = N) {
    		if(!v.size()) v.pb(0);
    		if(v.size() > len) v.resize(len);
    		int t = v.size() - 1;
    		while(t && v[t] == 0) {v.pop_back();--t;}
    		return *this;
    	}
    	friend Poly operator + (Poly a,Poly b) {
    		int h = max(a.v.size(),b.v.size());
    		a.v.resize(h);b.v.resize(h);
    		Poly c;
    		for(int i = 0 ; i < h ; ++i) {
    			c.v.pb(inc(a.v[i],b.v[i]));
    		}
    		return c;
    	}
    	friend Poly operator - (Poly a,Poly b) {
    		int h = max(a.v.size(),b.v.size());
    		a.v.resize(h),b.v.resize(h);
    		Poly c;
    		for(int i = 0 ; i < h ; ++i) {
    			c.v.pb(inc(a.v[i],MOD - b.v[i]));
    		}
    		return c;
    	}
    	friend void NTT(Poly &a,int L,int on) {
    		a.v.resize(L);
    		for(int i = 1 ,j = L >> 1 ; i < L - 1 ; ++i) {
    			if(i < j) swap(a.v[i],a.v[j]);
    			int k = L >> 1;
    			while(j >= k) {
    				j -= k;
    				k >>= 1;
    			}
    			j += k;
    		}
    		for(int h = 2 ; h <= L ; h <<= 1) {
    			int wn = W[(MAXL + MAXL / h * on) % MAXL];
    			for(int k = 0 ; k < L ; k += h) {
    				int w = 1;
    				for(int j = k ; j < k + h / 2 ; ++j) {
    					int u = a.v[j],t = mul(a.v[j + h / 2],w);
    					a.v[j] = inc(u,t);
    					a.v[j + h / 2] = inc(u,MOD - t);
    					w = mul(w,wn);
    				}
    			}
    		}
    		if(on == -1) {
    			int InvL = fpow(L,MOD - 2);
    			for(int i = 0 ; i < L ; ++i) a.v[i] = mul(a.v[i],InvL);
    		}
    	}
    	friend Poly operator * (const int &a,const Poly &b) {
    		Poly c;int l = b.v.size();
    		for(int i = 0 ; i < l ; ++i) c.v.pb(mul(a,b.v[i]));
    		return c;
    	}
    	friend Poly operator * (Poly a,Poly b) {
    		Poly c;
    		int t = a.v.size() + b.v.size(),l = 1;
    		while(l <= t) l <<= 1;
    		a.v.resize(l);b.v.resize(l);
    		NTT(a,l,1);NTT(b,l,1);
    		c.v.resize(l);
    		for(int i = 0 ; i < l ; ++i) c.v[i] = mul(a.v[i],b.v[i]);
    		NTT(c,l,-1);
    		return c.limit();
    	}
    	friend Poly inverse(Poly a,int t) {
    		if(t == 1) return Poly(fpow(a.v[0],MOD - 2));
    		a.limit(t);
    		Poly b = inverse(a,t >> 1);
    		int l = b.v.size() + b.v.size() + a.v.size();
    		int len = 1;
    		while(len <= l) len <<= 1;
    		NTT(b,len,1);NTT(a,len,1);
    		Poly c;c.v.resize(len);
    		for(int i = 0 ; i < len ; ++i) c.v[i] = inc(mul(2,b.v[i]),MOD - mul(mul(b.v[i],b.v[i]),a.v[i]));
    		NTT(c,len,-1);
    		return c.limit(t);
    	}
    	friend Poly Inverse(const Poly &a,int t = N) {
    		int l = 1;
    		while(l < t) l <<= 1;
    		return inverse(a,l).limit(t);
    	}
    	friend Poly sub_sqrt(Poly a,int t) {
    		if(t == 1) return Poly(Cipolla::Sqrt(a.v[0]));
    		a.limit(t);
    		Poly b = sub_sqrt(a,t >> 1);
    		Poly inv = 2 * b;inv.v.resize(t);inv = Inverse(inv,t);
    
    		int l = inv.v.size() + max(b.v.size() + b.v.size(),a.v.size()),len = 1;
    		while(len <= l) len <<= 1;
    		NTT(inv,len,1);NTT(b,len,1);NTT(a,len,1);
    		Poly c;c.v.resize(len);
    		for(int i = 0 ; i < len ; ++i) {
    			c.v[i] = mul(inc(a.v[i],mul(b.v[i],b.v[i])),inv.v[i]);
    		}
            NTT(c,len,-1);
    		return c.limit(t);
    	}
    	friend Poly Sqrt(const Poly &a,int t = N) {
    		int l = 1;
    		while(l < t) l <<= 1;
    		return sub_sqrt(a,l).limit(t);
    	}
    	friend Poly Derivative(const Poly &a) {
    		Poly c;c.v.resize(a.v.size() - 1);
    		for(int i = 0 ; i < a.v.size() - 1 ; ++i) {
    			c.v[i] = mul(a.v[i + 1],i + 1);
    		}
    		return c;
    	}
    	friend Poly Integral(const Poly &a) {
    		Poly c;c.v.resize(a.v.size() + 1);
    		for(int i = 1 ; i <= a.v.size() ; ++i) {
    			c.v[i] = mul(a.v[i - 1],Inv[i]);
    		}
    		return c;
    	}
    	friend Poly ln(Poly a,int t = N) {
    		Poly c = Inverse(a,t),d = Derivative(a);
    		int l = c.v.size() + d.v.size(),len = 1;
    		while(len <= l) len <<= 1;
    		NTT(c,len,1);NTT(d,len,1);
    		Poly res;res.v.resize(len);
    		for(int i = 0 ; i < len ; ++i) res.v[i] = mul(c.v[i],d.v[i]);
    		NTT(res,len,-1);
    		return Integral(res).limit(t);
    	}
    	friend Poly sub_exp(Poly a,int t) {
    		if(t == 1) {return Poly(1);}
    		a.limit(t);
    		Poly b = sub_exp(a,t >> 1);
    		Poly lnb = ln(b,t);
    		int l = b.v.size() + max(lnb.v.size(),a.v.size()),len = 1;
    		while(len <= l) len <<= 1;
    		NTT(lnb,len,1);NTT(b,len,1);NTT(a,len,1);
    		Poly c;c.v.resize(len);
    		for(int i = 0 ; i < len ; ++i) {
    			c.v[i] = inc(b.v[i],mul(b.v[i],inc(a.v[i],MOD - lnb.v[i])));
    		}
    		NTT(c,len,-1);
    		return c.limit(t);
    	}
    	friend Poly Exp(Poly a) {
    		int l = 1;
    		while(l < a.v.size()) l <<= 1;
    		return sub_exp(a,l).limit();
    	}
    	friend Poly operator ^ (const Poly &a,const int &k) {
    		return Exp(k * ln(a)).limit();
    	}
    	friend void Print(const Poly &a) {
    		for(int i = 0 ; i < a.v.size() ; ++i) {
    			out(a.v[i]);space;
    		}
    		enter;
    	}
    }F,G;
    void Solve() {
    	read(N);read(K);
    	int a;
    
    	for(int i = 0 ; i <= N ; ++i) {
    		read(a);
    		F.v.pb(a);
    	}
    	Inv[1] = 1;W[0] = 1;W[1] = fpow(3,(MOD - 1) / MAXL);
    	for(int i = 2 ; i < MAXL ; ++i) {
    		W[i] = mul(W[i - 1],W[1]);
    		Inv[i] = mul(Inv[MOD % i],MOD - MOD / i);
    	}
    	int tip = N;
    	N++;
    	G = Derivative((Poly(1) + ln(Poly(2) + F - Poly(F.v[0]) - Exp(Integral(Inverse(Sqrt(F))))))^K);
    	G.v.resize(tip);
    	Print(G);
    	enter;
    }
    int main() {
    #ifdef ivorysi
    	freopen("f1.in","r",stdin);
    #endif
    	Solve();
    }
    
  • 相关阅读:
    Security Group: Domain Local, Global, 和Universal 有什么区别?
    如何在EXCEL中运行SQL查询?
    SharePoint中的图标icon配置
    STSADM 命令使用大全
    SharePoint中的诊断日志记录(也就是ULS)
    SharePoint incoming email的计划与配置
    CSV文件格式
    Builtin\administrators 与 Domain Admins 用户组的来历与区别
    SQL Alias 的配置和使用
    Windows平台上的环境变量
  • 原文地址:https://www.cnblogs.com/ivorysi/p/10273273.html
Copyright © 2020-2023  润新知