「学习笔记」基础多项式科技

多项式复合

这东西 \(O(n^2+n\sqrt n\log n)\) 过了 \(20000\)

思路是非常精巧的,令 \(L=\sqrt n\) 考虑每个次幂的对系数的贡献那么得到一个式子

\[\sum_{i=0}^L G^{iL}\sum_{j=0}^{L-1}G^jF[x^{iL+j}] \]

分块预处理 \(G\) 的大块和小块就行了

那么这个算是数据结构维护分段多项式的入门题

多项式复合逆

考虑复合的过程和复合逆的过程是类似的

\[G(x)=\sum_{i=0}^L\frac{1}{iL}(\frac{x}{F(x)})^{iL} \sum_{j=0}^{L-1} \frac1j (\frac{x}{F(x)})^{j} \]

这个做法的正确性如下

Lagrange反演&扩展Lagrange反演

普通反演看懂了,扩展反演没人写证明

式子如下:

\[G(F(x))=x\to [x^n]G(x)=\frac1{n} [x^{n-1}] (\frac{x}{F(x)})^n \]

证明并不是 \(trivial\) 的,考虑将 \(G(F(x))=x\) 的式子展开并求导得到

\[\sum F^{i-1}(x) ia_iF'(x)=1 \]

考虑反演本身的式子可以消掉 \(x^n\) 那么保留 \(x^{-1}\) 和常数项来观察

由于多项式函数求导以后 \(x^{-1}\) 的系数总是 \(0\)(导数定义),那么考虑对展开的式子除掉 \(F^n(x)\) 并得到 \(x^{-1}\) 的系数有:

\[F^{-1}(x)F'(x)[x^{-1}]=[x^{-1}] \frac{1}{F^n(x)} \]

对于左边而言,接着展开两个函数的乘积就可以得到 \(x^{-1}\) 的系数必然为 \(1\)

带入得到原反演式子,证毕

\[H(F(x))[x^n]=\frac1n [x^{-1}] H'(x)\frac1 {G^n(x)} \]

多项式多点求值

\(F(x)=G(x)Q(x)+R(x)\),那么对于任意一个 \(x_0\) 都会有

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

\(G(x_0)=0\)\(F(x_0)=R(x_0)\)

那么设 \(P_0(x)=\prod_{i=0}^{n/2} x-x_i,P_1(x)=\prod_{i=n/2+1}^n x-x_i\)

\(F(x)\) 不停地对去区间的乘积取模就可以最后剩下常数作为答案

分治乘法作预处理,再 \(dfs\) 一次得到所有答案

这里取模的时候千万注意清空

代码如下:

Code Display
namespace Multi_Evaluation{
	vector<int> P[N];
    inline void prework(int p,int l,int r){
        if(l==r){P[p]={mod-qu[l],1}; return ;}
        int mid=(l+r)>>1; prework(p<<1,l,mid); prework(p<<1|1,mid+1,r);
        P[p]=Mul(P[p<<1],P[p<<1|1]);
		return ;
    }
    inline void solve(int p,int l,int r,vector<int> f){
        if(l==r) return ans.push_back(f[0]),void(); int mid=(l+r)>>1;
        solve(p<<1,l,mid,Mod(f,P[p<<1])); 
		solve(p<<1|1,mid+1,r,Mod(f,P[p<<1|1]));
        return ;
    }
    void solve(){
        int n=f.size()-1,m=qu.size();
        prework(1,0,m-1); 
		solve(1,0,m,n>=m?Mod(f,P[1]):f);
        return ;
    }
}

这样 \(1s\ 6e4\) 都跑不了,可行的优化手段,设

\[Mul(F(x),G(x))=\sum_i (sum_j f_{i+j}g_j)x^i \]

所以 \(F(x_i)=[z^0]Mul(F(z),\frac{1}{1-x_iz})\),还是分治,那么每次传入的变成了:

\[Mul(F(z),\frac1{\prod (1-x_iz)}) \]

那么每次递归下去的是时候利用 乘另外半边的乘积并且保留区间长度的项数就可以了

用多项式乘法代替了取模,快了很多

多项式快速插值

根据朴素的 \(Lagrange\) 插值法可以得到一个公式:

\[F(x)=\sum_{i=1} ^n y_i \prod_{j\neq i}\frac{x-x_j}{x_i-x_j} \]

但是显然暴力乘开是 \(O(n^2)\) 的,那么考虑分治

设多项式 \(p(l,r)=\prod_{i=l}^r x-x_i,v(l,r)=\sum_{i=l}^r y_i\prod_{j\neq i} \frac{x-x_j}{x_i-x_j}\)

容易发现递推公式 \(v(l,r)=v(l,mid)p(mid+1,r)+v(mid+1,r)p(l,mid)\)

但是瓶颈在于对每个 \(i\) 求这个 \(\frac{1}{\prod_{j\neq i} x_i-x_j}\),设 \(G(x)=\prod x-x_i\),所以前面所求就是 \(\frac{x-x_i}{G(x)}\)

带入 \(x=x_i\) 发现上下同时是 \(0\),所以使用洛必达法则来处理,问题就变成了多点求值

Code Display
namespace Quick_interploration{
    poly X,Y,T[N<<2],res;
    inline void prework(int p,int l,int r){
        if(l==r) return T[p]={mod-X[l],1},void(); int mid=(l+r)>>1;
        prework(p<<1,l,mid); prework(p<<1|1,mid+1,r); 
        T[p]=Mul(T[p<<1],T[p<<1|1]);
        return ;
    }
    inline poly dfs(int p,int l,int r){
        if(l==r) return {mul(Y[l],ksm(res[l],mod-2))};
        int mid=(l+r)>>1;
        return Plus(Mul(dfs(p<<1,l,mid),T[p<<1|1]),Mul(dfs(p<<1|1,mid+1,r),T[p<<1]));
    }
    inline poly query(poly x,poly y){
        X=x; Y=y; int n=x.size()-1; prework(1,1,n);
        T[1]=deriv(T[1]); T[1].push_back(0);
        res=Multi_Evaluaiton::query(T[1],x);
        return dfs(1,1,n);
    }
}
posted @ 2021-02-03 21:33  yspm  阅读(178)  评论(0编辑  收藏  举报