zoukankan      html  css  js  c++  java
  • 关于多项式的一些东西

    泰勒展开

    (f(x))(x_0)处可导,且存在无穷阶导数,那么根据泰勒展开,有:

    [f(x) = sum_{i=0}^{inf} frac{f^{[i]}(x_0)}{i!}(x-x_0)^i + delta ]

    其中(delta)是一个余项,表示一个趋近于无穷小的误差。每展开一项,误差就越小。
    (f(x))(x_0 = 0)处可导,带入泰勒展开式后可以得到(f(x))的麦克劳林展开式:

    [f(x) = sum_{i=0}^{inf} frac{f^{[i]}(0)}{i!}x^i + delta ]

    一般来说,信息学奥赛中都会使用麦克劳林展开式。我们可以将(e^x)用麦克劳林展开:

    [e^x = 1 + frac{x}{1!} + frac{x^2}{2!} + ... + delta = sum_{i=0}^{inf} frac{x^i}{i!} + delta ]

    这个式子将在后面反复用到,是非常重要的式子。

    牛顿迭代法

    给定一个关于(B(x))的函数(F),求(F(B(x)) = 0(mod x^t))
    我们令(B_t(x))表示模(x^{2^{t}})意义下的一个解。
    那么,对(F(B_{t+1}(x)))(B_{t}(x))处进行泰勒展开有:

    [F(B_{t+1}(x)) = F(B_t(x)) + frac{F'(B_t(x))}{1!} (B_{t+1}(x) - B_t(x))..... ]

    (deg(B_{t+1}(x) - B_t(x))^2 = 2^{t+2}-1geq 2^{t+1})
    所以除了最前面的两项,其他项的结果都为(0)
    所以

    [F(B_{t+1}(x)) = F(B_t(x)) + frac{F'(B_t(x))}{1!} (B_{t+1}(x) - B_t(x)) ]

    化简可得:

    [B_{t+1}(x) = B_{t}(x) - frac{F(B_t(x))}{F'(B_t(x))} ]

    利用牛顿迭代,我们就能够解决多项式的各种基本运算了。

    多项式基本运算

    乘法就不说了,(FFT)(NTT)(MTT)、分治(FFT)等 都是基本功。

    多项式求导与积分

    • 求导((c(x^a))' =cax^{a-1})
    • 积分(int cx^a = frac{cx^{a+1}}{a+1})

    求导后,默认最高项等于(0)。积分后,默认最低项等于(0)

    多项式求逆

    牛顿迭代得出的运算重点推导这一个,剩下的全部以给公式的形式呈现。
    (A_t(x)B_{t-1}(x) = 1 o A_t(x)B_{t-1}(x) - 1 = 0)
    然后套牛顿迭代就行了:

    [B_{t}(x) = B_{t-1}(x) - frac{A_t(x)B_{t-1}(x) - 1}{A_t(x)} = 2B_{t-1}(x) - A_t(x)B_{t-1}^2(x) ]

    多项式(A(x))存在逆的条件:常数项( eq 0)
    注意一下,由于(B_t(x))(A_t(x))的第(2^{t})项是没有值的,所以传参(len)时可以减少一倍。

    多项式求(ln)

    不需要牛顿迭代推出的运算重点推导这一个,剩下的全部以给公式的形式呈现。
    (lnA(x) = B(x) o B'(x) = frac{A'(x)}{A(x)})
    然后好像就没了......求逆后积分回去就行了。

    其余多项式运算

    全部给公式了,推导都是一样的。

    • 快速幂:(B(x) = e^{K ln(A(x))})
    • 开根:(B_t(x) = frac{1}{2}(B_{t-1}(x) + frac{A_t(x)}{B_{t-1}(x)}))
    • (exp)(B_t(x) = B_{t-1}(x)(1 - ln(B_{t-1}(x)) + A_t(x)))

    注意一下,求(ln)前常数项必须为(1),求(exp)前常数项必须为(0)

    多项式除法

    给定一个(n)次多项式(F(x))(m)次多项式(G(x))
    求一个(n-m)次多项式(C(x))(m-1)次多项式(R(x)),满足(F(x) = G(x)C(x)+R(x))
    定义操作(A^R(x) = x^n A(frac{1}{x})),即将多项式的所有系数反转过来。
    那么:

    [x^nF(frac{1}{x}) = x^m G(frac{1}{x})*x^{n-m} C(frac{1}{x}) + x^{n-m+1}x^{m-1}R(frac{1}{x}) ]

    所以:(F^R(x) = G^R(x)C^R(x) + x^{n-m+1} R^R(x))
    所以有:

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

    所以(C^R(x) = frac{F^R(x)}{G^R(x)} (mod x^{n-m+1})),多项式求逆即可。
    得到(C(x))后,(R(x) = F(x) - G(x)C(x))

    代码实现的时候,对于模(x^{n-m+1})意义下的多项式,一定要及时清空多余项,防止之后的(NTT)出问题。

    IL void MOD(int *a , int *b) {
    	N = 2 * (K - 1) ; M = K ;
    	for(Len = 1; Len <= K; Len <<= 1) ;
    	for(int i = 0; i < K; i ++) f3[i] = a[i] , f4[i] = b[i] ;
    	NTT(f3 , 1 , Len << 1) ; NTT(f4 , 1 , Len << 1) ;
    	for(int i = 0; i < nn; i ++) f3[i] = 1ll * f3[i] * f4[i] % mod ;
    	NTT(f3 , -1 , Len << 1) ;
        reverse(f3 , f3 + N + 1) ; reverse(C , C + M + 1) ;
    	for(Len = 1; Len <= N; Len <<= 1) ; 
    	Poly_Inv(C , InvC , Len) ;
    	for(int i = N - M + 1; i <= Len; i ++) InvC[i] = 0 ;   //!!!!!!!!!!!!!!!!!!!!!!!!!
    	NTT(f3 , 1 , Len << 1) ; NTT(InvC , 1 , Len << 1) ;
    	for(int i = 0; i < nn; i ++) G[i] = 1ll * f3[i] * InvC[i] % mod ;
    	NTT(G , -1 , Len << 1) ;
    	NTT(f3 , -1 , Len << 1) ;
    	for(int i = N - M + 1; i <= Len; i ++) G[i] = 0 ;      //!!!!!!!!!!!!!!!!!!!!!!!!!
    	reverse(f3 , f3 + N + 1) ; reverse(G , G + (N - M) + 1) ; reverse(C , C + M + 1) ;
    	NTT(C , 1 , Len << 1) ; NTT(G , 1 , Len << 1) ;
    	for(int i = 0; i < nn; i ++) G[i] = 1ll * G[i] * C[i] % mod ;
    	NTT(G , -1 , Len << 1) ;
    	NTT(C , -1 , Len << 1) ;
    	for(int i = 0; i < M; i ++) a[i] = (f3[i] - G[i] + mod) % mod ;
    	for(int i = 0; i < (Len << 1) ; i ++) InvC[i] = G[i] = f3[i] = f4[i] = 0 ;
    }
    

    多项式乘法在串匹配中的应用

    特征:字符集极小或存在通配符
    建模技巧:

    • 允许存在不超过(K)的偏移量:直接将当前枚举字符向左右扩展(K)格(差分实现)。
    • 存在通配符:令通配符(S_i = T_j = 0)
      则把匹配条件变为(0 = sum_{i=1}^{|T|} (S_{i+st} - T_i)T_iS_{i+st}),拆式子后(FFT)

    匹配方法:

    • 常规匹配:形如(i_S - j_T = c),反向(FFT)/(NTT)处理
    • 对称匹配:形如(i_S + j_S = 2 * k_T),正向(FFT)/(NTT)处理。

    这类题目只要认真分析+胡思乱想总能想出来的,关键还是在于对字符串的理解。

    生成函数简介

    生成函数就是母函数。
    母函数可以推导递推公式的通项公式,但是那一套就不说了,跟多项式关系也不大。
    生成函数有两种,普通型(G(x) = sum_{i=0}^{inf} g_i x^i)与指数型(F(x) = sum_{i=0}^{inf} f_i frac{x^i}{i!})
    一般来说,有序问题会使用指数型,而组合问题会使用普通型。
    普通型没啥好说的吧......
    指数型母函数就是(e^x)的展开式,故可以有一些骚套路:

    • (e^{-x} = 1 - frac{x}{1!} + frac{x^2}{2!} - frac{x^3}{3!}......)
    • 只要奇数项:(frac{e^x - e^{-x}}{2})
    • 只要偶数项:(frac{e^x + e^{-x}}{2})
    • (e^{nx} = 1 + frac{(nx)}{1!} + frac{(nx)^2}{2!} + frac{(nx)^3}{3!}......)

    指数型母函数的系数本质就是多了一个可重排列(frac{(sum_{i=1}^ma_i)!}{a_1!a_2!...a_m!})
    我们使用泰勒展开还可以得到广义二项式定理:

    • $(1+x)^m = 1 + frac{m}{1!} x + frac{m(m-1)}{2!}x^2 + ... + frac{m(m-1)...2*1}{m!} x^m $
    • ((1-x)^m = 1 - frac{m}{1!} x + frac{m(m-1)}{2!} x^2 - frac{m(m-1)(m-2)}{3!}x^3 + ... frac{m(m-1)...2*1}{m} x^m)
    • ((1+x)^m = inom{m}{m} + inom{m}{m-1}x + inom{m}{m-2}x^2 +... inom{m}{0} x^m)
    • ((1-x)^m = inom{m}{m} - inom{m}{m-1}x + inom{m}{m-2}x^2 + ... inom{m}{0} x^m)

    这玩意儿在手算题里有奇效,得到形如(frac{1}{(1-x)^k})的生成函数后,可以通过这个直接得到第(r)项系数。
    最后:
    关于选择、组合问题请多想生成函数!!!
    关于选择、组合问题请多想生成函数!!!
    关于选择、组合问题请多想生成函数!!!

    若干有用的科技/套路

    简单(单项)多项式手动求(ln)

    当出现求(ln F(x)),其中(F(x))只包含一个形如(x^t)的项时,可以考虑手动求(ln)
    手动求(ln)的方法为:先求导,然后把分母展开为生成函数,最后积分得到答案。
    给一个例子:(F(x) = ln (1-x^t))

    [F(x) = int F'(x) = int frac{-tx^{t-1}}{1-x^t} = int -tx^{t-1} sum_{i=0}^{inf} x^{ti} ]

    继续:

    [F(x) = -int sum_{i=0}^{inf} tx^{t(i+1)-1} = -sum_{i=1}^{inf}frac{tx^{ti}}{ti} = -sum_{i=1}^{inf} frac{x^{ti}}{i} ]

    这个技巧可谓是相当相当相当的关键了,下面的一些推导中,还会反复使用到这个技巧。

    组合关系的生成函数拆分

    给定一个形如(h_x = sum_{i=0}^{n} inom{n}{i}f_ig_{n-i})
    (h_i)(g_i)好求,需要求(f_i),那么我们可以把组合数拆开后这么做:

    [frac{h_n}{n!} = sum_{i=0}^n frac{f_i}{i!} frac{g_{n-i}}{(n-i)!} ]

    接着构造生成函数(H(x) =sum_{i=0}^{inf} frac{h_i}{i!}x^i)(F(x)=sum_{i=0}^{inf} frac{f_i}{i!}x^i)(G(x)=sum_{i=0}^{inf} frac{g_i}{i!}x^i)
    那么有(H(x) = F(x)G(x))
    所以(F(x) = frac{H(x)}{G(x)}),通过多项式求逆得到(F(x))后即可得到(f_i)

    划分关系与指数型生成函数

    (F(x) = sum_{i=1}^n f_i frac{x^i}{i!}),其中(f_i)表示(i)个元素的(A)集合的种类数。
    同理我们设(G(x) = sum_{i=0}^n g_i frac{x^i}{i!}),其中(g_i)表示(i)个元素的(B)集合的种类数。
    若所有元素都有编号,且(B)集合是由若干(A)集合构成的,那么有:

    [G(x) = e^{F(x)} ]

    几个例子:

    • (F(x))为简单有向联通图的生成函数,(G(x))为简单有向图的生成函数。
    • (F(x))为要求联通的(DAG)的生成函数,(G(x))为不要求联通的(DAG)的生成函数。

    证明:把(e^{F(x)})泰勒展开后有:(e^{F(x)} = sum_{i=0}^n frac{F(x)^i}{i!})
    然后我们考虑(G(x))中的每一项的构成:

    [[x^n]G(x) = x^nsum_{k=1}^n frac{[x^n](F(x)^k)}{k!} = x^nsum_{k=1}^n [frac{frac{f_{a_1}f_{a_2}...f_{a_k}}{a_1!a_2!...a_k!}}{k!}] = frac{x^n}{n!} sum_{k=1}^n [(frac{f_{a_1}f_{a_2}...f_{a_k}}{a_1!a_2!...a_k!})frac{n!}{k!}] ]

    可以注意到(frac{n!}{a_1!a_2!...a_k!})正是可重排列编号的方案数,而(frac{1}{k!})对应构成(B)(A)集合之间无顺序关系。

    快速求(G(x) = prod_i^m frac{1}{(1-x^{t_i})} (mod x^{n}))

    一般的背包问题其实就是若干(T(x) = frac{1}{1-x^{V_i}})卷起来,所以这个东西可以解决背包问题。
    显然不能直接分治(NTT),但我们可以在(O(nln(n)+nlog^2n))的时间内求出这个式子。
    (F_i(x) = frac{1}{(1-x^{t_i})}),那么

    [G(x) = e^{sum_{i=1}^m ln(F_{i}(x))} ]

    所以只需要求的(Ans(x) = sum_{i=1}^m ln(F_{i}(x)))后再多项式(exp)即可得到(G(x))
    考虑求(Ans(x) = sum_{i=1}^m ln(F_i(x))),显然不能对每一项直接求(ln)
    我们尝试两边求导得:(Ans = int sum_{i=1}^m (ln(F_{i}(x)))')。然后化简((ln(F_i(x)))')有:

    [(lnF_i(x))' = frac{F_i'(x)}{F_i(x)} = (1-x^{t_i})(sum_{j=0} x^{jt_i})' = (1-x^{t_i})(sum_{j=1} t_ijx^{jt_i-1}) ]

    把上式错位相减后有:((lnF_i(x))' =sum_{j = 1} t_i x^{jt_i - 1}),所以有:

    [Ans(x) = int sum_{i=1}^m(lnF_i(x))' = sum_{i=1}^m int sum_{j=1} t_ix^{jt_i-1} = sum_{i=1}^m sum_{j=1} frac{x^{jt_i}}{j} ]

    于是乎,首先统计每种(t)的数量(cnt_{t}),然后暴力给(Ans(x))加贡献即可,复杂度调和级数。

    快速求(sum_{i=1}^n a_i^k , kin[1,t])

    (O(nk))显然是假的,这辈子都不可能这么简单的。
    构造(F(x) = prod_{i=1}^n (a_ix + 1))
    那么(lnF(x) = sum_{i=1}^n ln(a_ix+1)),考虑手动求(ln)

    [ln(a_ix+1) = int frac{a_i}{1+a_ix} = a_i int sum_{j=0}^{inf}(-a_i)^j x^j = sum_{j=1}^{inf}frac{(-1)^{j-1}}{j}a_i^jx^j ]

    所以(lnF(x) = sum_{i=1}^n sum_{j=1}^{inf} frac{(-1)^{j-1}}{j}a_i^j x^j = sum_{j=1}^{inf}frac{(-1)^{j-1}}{j} sum_{i=1}^n a_i^j x^j)
    (F(x))可以同过分治(FFT)求出,所以求出(F(x))后,对(F(x))(ln)得到每一项的系数即可。

    快速求(sum_{i=1}^n sum_{j=1}^m (a_i + b_j)^k , kin [1,t])

    把式子暴力化开:(f(x) = sum_{i=1}^n sum_{j=1}^m (a_i + b_j)^x = sum_{i=1}^n sum_{j=1}^m sum_{k=0}^x a_i^k b_j^{x-k} inom{x}{k})
    所以有:

    [f(x) = x!sum_{k=0}^x frac{sum_{i=1}^n a_i^k}{k!} frac{sum_{j=1}^m b_j^{x-k}}{(x-k)!} ]

    而我们已经会快速求(sum_{i=1}^n a_i^k)了,所以只需要构造卷积再套一次(FFT)即可。

  • 相关阅读:
    软件对标分析
    第一阶段绩效评估
    自律小帮手:Alpha版使用说明
    团队 电梯演讲 原型展示
    意见评论
    Alpha版(内部测试版)发布
    意见汇总
    产品对比
    团队项目-第二阶段冲刺-3
    团队项目-第二阶段冲刺-2
  • 原文地址:https://www.cnblogs.com/GuessYCB/p/10126271.html
Copyright © 2011-2022 走看看