zoukankan      html  css  js  c++  java
  • 多项式求逆学习笔记

    前言:

    今天学习了多项式求逆,总结一下。
    这里是网上好的博客

    问题:

    给定一个多项式(A(x)),求出多项式(B(x)),使(A(x)B(x) equiv 1 pmod{x^n})

    解析:

    考虑递推求解,假设我们已经求出(B'(x)),使

    [A(x)B'(x) equiv 1 pmod{x^{lceil frac{n}{2} ceil}} ]

    又:

    [A(x)B(x) equiv 1 pmod{x^n} ]

    所以:

    [B(x)-B'(x) equiv 0 pmod{x^{lceil frac{n}{2} ceil}} ]

    将式子两边平方,有:

    [B(x)^2-2B(x)B'(x)+B'(x)^2 equiv 0 pmod{x^n} ]

    这里说明为何模数变成了(n),设(G(X)=(B(x)-B'(x))^2),那么第(i)个系数(a_i = sum_{j=0}^{i} c_j imes c_{i-j}),因为原来在(0)({lceil {frac{n}{2}} ceil})中系数(c_i)均为0,所以每一项其中必然有一项(c_i)为0。

    那么我们就得到了递推式:

    [B(x) equiv 2B'(x)-A(x) B'(x)^2 pmod{x^n} ]

    FFT优化乘法即可。

    时间复杂度:

    [T(n)=T(n/2)+O(nlogn),T(n)=O(nlogn) ]

    代码实现

    
    #include<bits/stdc++.h>
    #define N 300005
    using namespace std;
    const int P=998244353,G=3;
    int n,lim,l,a[N],b[N],c[N],r[N];
    inline int In(){
    	char c=getchar(); int x=0,ft=1;
    	for(;c<'0'||c>'9';c=getchar()) if(c=='-') ft=-1;
    	for(;c>='0'&&c<='9';c=getchar()) x=x*10+c-'0';
    	return x*ft;
    }
    inline int power(int x,int k){
    	int s=1,t=x;
    	for(;k;k>>=1,t=1ll*t*t%P) if(k&1) s=1ll*s*t%P;
    	return s;
    }
    void NTT(int *a,int op) {
        for(int i=0;i<lim;++i) if(i<r[i]) swap(a[i],a[r[i]]);
        for(int i=1;i<lim;i<<=1) {
            int Wn=power(G,(P-1)/(i<<1)); if(op<1) Wn=power(Wn,P-2);
            for(int j=0;j<lim;j+=(i<<1)) {
                int w=1;
                for(int k=0;k<i;++k,w=1ll*w*Wn%P) {
                    int x=a[j+k],y=1ll*w*a[j+k+i]%P;
                    a[j+k]=(x+y)%P; a[j+k+i]=(x-y+P)%P;
                }
            }
        }
        if(op==-1){
        	int inv=power(lim,P-2);
    	    for(int i=0;i<lim;++i) a[i]=1ll*a[i]*inv%P;
    	}
    }
    inline void Sol(int k){
    	if(k==1){ b[0]=power(a[0],P-2); return; }
    	Sol((k+1)/2);
    	lim=1; l=0; while(lim<2*k) lim<<=1,++l;
    	for(int i=1;i<lim;++i) r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
    	for(int i=0;i<k;++i) c[i]=a[i]; for(int i=k;i<lim;++i) c[i]=0;
    	NTT(b,1); NTT(c,1);
    	for(int i=0;i<lim;++i) b[i]=1ll*(2-1ll*c[i]*b[i]%P+P)%P*b[i]%P;
    	NTT(b,-1); for(int i=k;i<lim;++i) b[i]=0;
    }
    int main(){
    	n=In(); for(int i=0;i<n;++i) a[i]=In(); Sol(n);
    	for(int i=0;i<n;++i) printf("%d%c",b[i],(i==n-1)?'
    ':' ');
    	return 0;
    }
    
    

    应用

    例1.预处理伯努利数。

    伯努利数的指数生成函数是:

    [sum_{i=0}^{infty}{ B_i frac{x^i}{ i!} = frac{x}{e^x-1}= frac{x}{sum_{i=0}^{infty}{ frac{x^i}{ (i+1)!}} }}$。 然后求出下面多项式的逆就可以得到伯努利数了。 例2.BZOJ3456 城市规划(权限题) 题意:给定$n$,求出$n$个顶点的简单无向连通图的个数。 解析:设$f(n)$表示$n$个顶点的简单无向连通图的个数,$g(n)$表示$n$个顶点的简单无向图的个数,那么显然有: $$g(n)=2^{C(n,2)}qquad(1)]

    考虑(g(n))的另一种计算方法,枚举1号点所在连通块的顶点个数,那么有:

    [g(n)=sum_{i=1}^{n} C(n-1,i-1) imes f(i) imes g(n-i) qquad (2) ]

    将(1)代入(2),有:

    [2^{C(n,2)}=sum_{i=1}^{n} C(n-1,i-1) imes f(i) imes 2^{C(n-i,2)} ]

    两边同时除以((n-1)!),有:

    [frac{2^{C(n,2)}}{(n-1)!}=sum_{i=1}^{n}{frac{f(i)}{(i-1)!} frac{2^{C(n-i,2)}}{(n-i)!}} ]

    定义:(P(x)=sum_{n=0}^{infty} frac{f(n+1)}{n!} x^n)(Q(x)=sum_{n=0}^{infty} frac{2^{C(n,2)}}{n!} x^n)(G(x)=sum_{n=0}^{infty} frac{2^{C(n+1,2)}}{n!} x^n)

    那么据上有:

    [G(x)=P(x)Q(x) ]

    因为是求(P(x))的第(n-1)项系数,考虑这个等式在模(x^n)下的意义:

    [G(x) equiv P(x)Q(x) pmod{x^n} ]

    那么有:

    [P(x) equiv G(x)^{-1}Q(x) pmod{x^n} ]

    多项式求逆即可。

  • 相关阅读:
    spring boot整合mybatis+mybatis-plus
    Spring Boot Shiro 权限管理
    Spring Boot 热部署(转)
    SpringBoot 使用yml配置 mybatis+pagehelper+druid+freemarker实例
    详解Spring Boot配置文件之多环境配置
    Java 泛型-泛型类、泛型方法、泛型接口、通配符、上下限
    mybatis中整合ehcache缓存框架的使用
    Java总结篇系列:Java泛型
    java中接口之间的继承
    Java中接口继承泛型接口
  • 原文地址:https://www.cnblogs.com/pkh68/p/10511988.html
Copyright © 2011-2022 走看看