zoukankan      html  css  js  c++  java
  • 多项式基础运算

    前置知识:NTT

    多项式乘法逆

    加减乘都完成了,我们还差一个除:

    数字在取模运算中的乘法,我们通常用求逆元来完成,所以我们先来看看多项式的乘法逆:

    考虑递归求解,我们要求的是\(F(x)\)满足

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

    假设我们已经求出了\(F_0(x)\)满足

    \[G(x)F_0(x)\equiv 1\pmod {x^\frac n2} \]

    又因为

    \[G(x)F(x)\equiv 1\pmod {x^\frac n2} \]

    \[F(x)-F_0(x)\equiv 0\pmod {x^\frac n2} \]

    两边平方得:

    \[F^2(x)+F_0^2(x)-2F(x)F_0(x)\equiv 0\pmod {x^n} \]

    左右两边同成\(G(x)\)得:

    \[G(x)F^2(x)+G(x)F_0^2(x)-2G(x)F(x)F_0(x)\equiv 0\pmod {x^n} \]

    因为

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

    所以

    \[F(x)+G(x)F_0^2(x)-2F_0(x)\equiv0\pmod{x^n} \]

    \[F(x) \equiv2F_0(x)-G(x)F_0^2(x)\pmod{x^n} \]

    然后就可以递归了,边界就是\(F(x)\)只有一项时,\(G(x)\)就是这一项的逆元。

    这里只给出了,求逆部分的代码,容器及\(NTT\)请参见我的上一篇博客

    inline poly getinv(int n,poly f){
    	if(n==1){poly g;g[0]=ksm(f[0],mod-2);return g;}
    	int t=(n+1)>>1;
    	poly g=getinv(t,f);poly p=g;
    	
    	int lim=1,len=0;
    	while(lim<(n<<1)) lim<<=1,len++;
    	for(int i=0;i<lim;++i) r[i]=(r[i>>1]>>1)|((i&1)<<(len-1));
    	if(f.size()>n) f.mem(n,min(lim,f.size())-1,0);
    	if(p.size()>n) p.mem(n,min(lim,g.size())-1,0);
    		
    	NTT(lim,f,1);NTT(lim,p,1);
    	f=f*p*p;
    	NTT(lim,f,-1);
    	int iv=ksm(lim,mod-2);
    	poly h;
    	for(int i=0;i<n;++i) h[i]=dec(2ll*g[i]%mod,1ll*f[i]*iv%mod);
    	return h;
    } 
    

    多项式对数函数(多项式ln)

    考虑求的是:

    \[B(x)=F(A(x)),F(x)=\ln\ x \]

    对两边求导:

    \[B'(x)=F'(A(x))A'(x)=\frac{A'(x)}{A(x)} \]

    这里用到了复合函数的求导法则:

    \[(F(G(x)))'=F'(G(x))G'(x) \]

    于是对\(A(x)\)求逆并求导,得到\(B'(x)\)后积分回去即可。

    根据求导的基本公式\((x^n)'=nx^{n-1}\),于是扫一遍就可以完成多项式的求导与积分(忽略我的函数名):

    int inv[N],tp=2;
    inline void init(int n){
    	if(tp==2) inv[0]=inv[1]=1;
    	for(tp;tp<=n;++tp)
    		inv[tp]=1ll*(mod-mod/tp)*inv[mod%tp]%mod; 
    }
    inline void getdao(int n,poly& f){
    	for(int i=1;i<n;++i) f[i-1]=1ll*i*f[i]%mod;
    	f[n-1]=0;
    }
    inline void jifen(int n,poly& f){
    	init(n);
    	for(int i=n-1;i;--i) f[i]=1ll*inv[i]*f[i-1]%mod;
    	f[0]=0;
    }
    

    \(\ln\)的代码就很简单了:

    inline poly getln(int n,poly f){
    	poly g=getinv(n,f);getdao(n,f);
    	poly h=poly_mul(n,n,f,g);
    	jifen(n,h);
    	return h;
    }
    

    多项式除法

    一般的除法,我们直接通过乘其乘法逆来解决,但有些时候,我们不仅要除,还要取模,这该怎么办呢:

    我们已知\(n\)次多项式\(F(x)\)\(m\)次多项式\(G(x)\),要求\(n-m\)次多项式\(Q(x)\)和小于\(m\)次的多项式\(R(x)\)满足

    \[F(x)=Q(x)G(x)+R(x) \]

    我们先引入一种新的操作,对于$n \(次多项式(注意\) n\(次多项式是最高次数为\) n \(的多项式,但在我的所有代码与题解中,我使用的\) n\(都表示最高次数为\)n-1$):

    \[F_R(x)=x^nF(\frac 1x) \]

    展开后可以发现:

    \[F_R(x)=f_0x^n+f_1x^{n-1}+f_2x^{n-2}+\dots+f_{n-1}x+f_n \]

    没错,这一操作就相当于翻转了\(F(x)\) 的系数,可以\(O(n)\)完成。

    利用这个操作,我们去推柿子:

    \[F(\frac 1x)=Q(\frac 1x)*G(\frac 1x)+R(\frac 1x)\\ \]

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

    \[F_R(x)=Q_R(x)G_R(x)+x^{n-m+1}R_R(x) \]

    因为\(x^{n-m+1}R_R(x)\)的前\(n-m+1\)项系数一定为\(0\),于是

    \[F_R(x)\equiv Q_R(x)G_R(x)\pmod{x^{n-m+1}}\\ Q_R(x)\equiv F_R(x)G_R^{-1}(x)\pmod{x^{n-m+1}} \]

    求一遍\(G(x)\)的逆,我们就算出\(Q_R(x)\),进而求出\(Q\)了。

    至于\(R(x)\),我们直接由

    \[R(x)=F(x)-Q(x)*G(x) \]

    求出


    以上是多项式比较基础的几个运算,更高阶的一些运算(如开根,\(\exp\)等)需要用到更高阶的知识——多项式牛顿迭代

  • 相关阅读:
    oracle shrink
    PL/SQL Developer登入时候报ORA-12638: 身份证明检索失败的解决办法
    Oracle11g搭建DataGuard及主备切换方法总结【亲测可用】
    Dataguard主、备库切换方法总结
    CentOS下的Mysql的安装和使用
    在HP-UX上部署oracle客户端
    ORACLE 清理SYSAUX表空间
    第02节-BLE协议各层的形象化理解
    第01节-生活中的实例_医院的结构
    仿照手机写一个WIFI的操作程序
  • 原文地址:https://www.cnblogs.com/tqxboomzero/p/14164978.html
Copyright © 2011-2022 走看看