首页 > 其他分享 >多项式模板整理

多项式模板整理

时间:2024-02-26 11:13:00浏览次数:34  
标签:frac zlt pmod 多项式 ll ln 整理 模板

约定

\(F[i]\) 表示 \(F(x)\) 的 \(i\) 次项系数。

多项式乘法基础

详情见 多项式乘法入门

多项式求逆

给出 \(n\) 次多项式 \(F(x)\),求一个多项式 \(G(x)\),满足 \(F(x)G(x)\equiv 1\pmod {x^n}\),\(G(x)\) 每个系数对 \(998244353\) 取模。

我们逐一递推,假设已知 \(G[1...i-1]\),需要求 \(G[i]\) 的值。若 \(i=1\),显然 \(G[1]=\frac1{F[1]}\);否则,有

\[\sum_{j=0}^iF[j]G[i-j]=0 \]

把带 \(G[i]\) 的提出来

\[F[0]G[i]+\sum_{j=0}^{i-1} F[j]G[i-j]=0 \]

\[G[i]=-\frac{\sum_{j=0}^{i-1}F[j]G[i-j]}{F[0]} \]

该算法的时间复杂度为 \(O(n^2)\)。

我们尝试使用 倍增法 求解。

若我们已知 \(\lfloor\frac n2\rfloor\) 次多项式 \(G_0(x)\) 满足

\[F(x)G_0(x)\equiv 1\pmod {x^{\lceil\frac n2\rceil}} \]

那么由于

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

模数变为 \(\lceil\frac n2\rceil\)

\[F(x)G(x)\equiv1\pmod{x^{\lceil\frac n2\rceil}} \]

两式相减得

\[F(x)(G(x)-G_0(x))\equiv 0\pmod{x^{\lceil\frac n2\rceil}} \]

\[G(x)-G_0(x)\equiv0\pmod{x^{\lceil\frac n2\rceil}} \]

为了把模数变为 \(n\),两边平方

\[(G(x)-G_0(x))^2\equiv0\pmod{x^n} \]

同时乘 \(F(x)\)

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

展开

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

带入 \(F(x)G(x)\equiv1\pmod {x^n}\)

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

移项得

\[G(x)\equiv2G_0(x)-F(x)G_0^2(x)\pmod{x^n} \]

其实也可以牛顿迭代。

点击查看代码
ll Q[maxn],P[maxn],o[maxn],t;
	void Getinv(ll *a,ll *b,ll n){
		for(ll i=0;i<n;i++) Q[i]=0; t=0;
		while(n>1) o[++t]=n, n=n+1>>1;
		Q[0]=power(a[0]); o[++t]=1;
		for(ll i=t-1;i;i--){
			for(ll j=0;j<o[i+1];j++) P[j]=Q[j];
			mul(P,P,P,o[i+1],o[i+1],o[i]);
			mul(a,P,P,o[i],o[i],o[i]);
			for(ll j=0;j<o[i];j++) Q[j]=(2*Q[j]-P[j]+mod)%mod;
		}
		for(ll i=0;i<o[1];i++) b[i]=Q[i];
	}

时间复杂度 \(O(n\log n)\)。

多项式求导与积分

求导:\(F'(x)=\sum_{i>0} f[i]\cdot i x^{i-1}\)

积分:\(\sum_{i>0} \frac{f[i-1]}i x^i\)

积分不会书写。

注意 \(F'(x)\not =(F(x))'\),可以设 \(y=F(x)\),容易得到 \((F(x))'=y'=0\)

多项式 \(\ln\)

计算 \(\ln F(x)\),设 \(G(x)=\ln F(x)\)。

两边同时求导

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

链式法则得

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

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

两边积分一下就行了,\(O(n\log n)\)。

点击查看代码
ll R[maxn];
	void ln(ll *a,ll *b,ll n){
		dao(a,R,n);
		Getinv(a,b,n);
		mul(b,R,R,n,n,n);
		jifen(R,b,n);
	}

多项式 \(\exp\)

设 \(F(G(x))=\ln G(x)-A(x)\),我们要求的是 \(G(x)\),满足方程 \(F(G(x))=0\)。

根据牛顿迭代,我们求出了 \(G_0(x)\equiv 0 \pmod x^{\lceil \frac n2 \rceil}\),由于 \(A(x)\) 是已知的东西,则

\[G(x)\equiv G_0(x)-\frac{F(G_0(x))}{F'(G_0(x))} \pmod {x^n} \]

\[G(x)\equiv G_0(x)-\frac{\ln G_0(x)-A(x)}{\ln 'G_0(x)} \pmod {x^n} \]

\[G(x)\equiv G_0(x)-\frac{\ln G_0(x)-A(x)}{\frac 1{G_0(x)}} \pmod {x^n} \]

\[G(x)\equiv G_0(x)-G_0(x)\cdot (\ln G_0(x)-A(x)) \pmod {x^n} \]

\[G(x)\equiv G_0(x)\cdot (1-\ln G_0(x)+A(x)) \pmod {x^n} \]

分治即可,\(O(n\log n)\)

点击查看代码
ll z[maxn],zlt,F[maxn],G[maxn];
	void Exp(ll *a,ll *b,ll n){
		zlt=0;
		for(ll i=0;i<n;i++) F[i]=0;
		while(n>1) z[++zlt]=n, n=n+1>>1;
		z[++zlt]=1; F[0]=1;
		for(ll i=zlt-1;i;i--){
			ln(F,G,z[i]);
			for(ll j=0;j<z[i];j++) G[j]=(a[j]<G[j]? a[j]+mod-G[j]:a[j]-G[j]);
			G[0]=(G[0]==mod-1? 0:G[0]+1);
			mul(F,G,F,z[i+1],z[i],z[i]);
		}
		for(ll i=0;i<z[1];i++) b[i]=F[i];
	}

多项式开根

设 \(F(G(x))=G^2(x)-A(x)\),求 \(F(G(x))=0\) 的解。

和 \(\exp\) 基本一模一样

\[G(x)\equiv G_0-\frac{F(G_0(x))}{F'(G_0(x))} \pmod {x^n} \]

\[G(x)\equiv G_0-\frac{G_0^2(x)-A(x)}{2G_0(x)} \pmod {x^n} \]

\[G(x)\equiv \frac{A(x)+G_0^2(x)}{2G_0(x)} \pmod {x^n} \]

点击查看代码
void Sqrt(ll *a,ll *b,ll n){
		zlt=0;
		for(ll i=0;i<n;i++) F[i]=0;
		while(n>1) z[++zlt]=n, n=n+1>>1;
		z[++zlt]=1; F[0]=1;
		for(ll i=zlt-1;i;i--){
			mul(F,F,G,z[i+1],z[i+1],z[i]);
			for(ll j=0;j<z[i];j++) G[j]=(G[j]+a[j]>=mod? G[j]+a[j]-mod:G[j]+a[j]);
			for(ll j=0;j<z[i+1];j++) F[j]=((F[j]<<1)>=mod? (F[j]<<1)-mod:F[j]<<1);
			Getinv(F,F,z[i]);
			mul(G,F,F,z[i],z[i],z[i]);
		}
		for(ll i=0;i<z[1];i++) b[i]=F[i];
	}

多项式除法

已知 \(F(x),G(x)\),解方程 \(F(x)=P(x)G(x)+Q(x)\),其中 \(\deg Q(x)<\deg G(x)\)。

若 \(\deg F(x)=n,\space \deg G(x)=m\),

推导:

\[F(\frac1x)=P(\frac1x)G(\frac1x)+Q(\frac1x) \]

\[x^nF(\frac1x)=x^nP(\frac1x)G(\frac1x)+x^nQ(\frac1x) \]

\[x^nF(\frac1x)=x^{n-m}P(\frac1x)*x^mG(\frac1x)+x^nQ(\frac1x) \]

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

上式中形如 \(D_R(x)\) 的多项式表示 \(D(x)\) 所有系数 reverse 后的多项式。

注意到右边有一项 \(x^{n-m+1}Q_R(x)\),当上式在模 \(x^{n-m+1}\)
意义下:

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

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

注意到 \(P_R(x)\) 的次数为 \(n-m\),于是一个求逆一个乘法可得 \(P_R(x)\),进而得到 \(P(x)\)。

带入 \(F(x)=P(x)G(x)+Q(x)\) 即可得到 \(Q(x)\)。

多项式快速幂

给出多项式 \(F(x)\) 和正整数 \(n,k\),求 \(F^k(x)\pmod n\)

考虑到 \(x^k=\exp(k\ln x)\),于是 \(F^k(x)=\exp(k\ln F(x))\),直接一个 \(\ln\) 一个 \(\exp\) 即可。

但是 \([x^0]F(x)\) 不一定为 \(1\),不能直接 \(\ln\),把多项式转换成 \(F(x)=x^ab*G(x)\) 的形式,于是 \(F^k(x)=x^{ak}b^kG^k(x)\),注意 \(k\) 在 \(b^k\) 中对 \(\varphi(mod)\) 取模。

常系数齐次线性递推

已知对于 \(n\ge k\),有 \(a_n=\sum\limits_{i=1}^k f_ia_{n-i}\),给出 \(f_{1...k},a_{0...k-1}\),求 \(a_n\)。

\(n\le10^9\)。

设 \(F(\sum\limits f_ix^i)=\sum f_ia_i\),答案即为 \(F(x^n)\)。

构造多项式 \(G(x)=x^k-\sum\limits_{i=0}^{k-1}f_{k-i}x^i\)。

显然,\(F(G(x))=F(x^k-\sum\limits_{i=0}^{k-1}f_{k-i}x^i)=a_k-\sum\limits_{i=0}^{k-1}f_{k-i}a_i=0\)

那么若 \(x^n=P(x)G(x)+Q(x)\),那么 \(F(x^n)=F(Q(x))\)。

这相当于多项式取模。但是 \(n\) 太大,我们可以用快速幂,把普通乘换成 \(\text{ntt}\),把普通取模换成多项式取模。

部分代码合集

点击查看代码
ll power(ll a,ll b=mod-2){
	ll s=1;
	while(b){
		if(b&1) s=s*a%mod;
		a=a*a%mod; b>>=1;
	} return s;
}
struct POLY{
	ll rev[maxn<<2], tr, inv[maxn<<2];
	void Getrev(ll n){
		if(tr==n) return; tr=n;
		for(ll i=1;i<n;i++)
			rev[i]=(rev[i>>1]>>1)|(i&1? n>>1:0);
	}
	void ntt(ll *a,ll n){
		Getrev(n);
		for(ll i=1;i<n;i++)
			if(i<rev[i]) swap(a[i],a[rev[i]]);
		for(ll i=1;i<n;i<<=1){
			ll g=power(3,(mod-1)/(i<<1));
			for(ll j=0;j<n;j+=(i<<1))
				for(ll k=0,g0=1;k<i;k++,g0=g0*g%mod){
					ll x=a[j|k], y=a[i|j|k]*g0%mod;
					a[j|k]=(x+y>=mod? x+y-mod:x+y), a[i|j|k]=(x<y? x+mod-y:x-y);
				}
		}
	}
	ll A[maxn<<2], B[maxn<<2];
	void mul(ll *a,ll *b,ll *c,ll n,ll m,ll k){
		for(ll i=0;i<n;i++) A[i]=a[i];
		for(ll i=0;i<m;i++) B[i]=b[i];
		ll l=1;
		while(l<n+m-1) l<<=1;
		ntt(A,l), ntt(B,l);
		for(ll i=0;i<l;i++) A[i]=A[i]*B[i]%mod;
		ntt(A,l), reverse(A+1,A+l);
		ll Inv=power(l);
		for(ll i=0;i<l;i++){
			if(i<k) c[i]=A[i]*Inv%mod;
			A[i]=B[i]=0;
		}
		for(ll i=l;i<k;i++) c[i]=0;
	}
	ll Q[maxn],P[maxn],o[maxn],t;
	void Getinv(ll *a,ll *b,ll n){
		for(ll i=0;i<n;i++) Q[i]=0; t=0;
		while(n>1) o[++t]=n, n=n+1>>1;
		Q[0]=power(a[0]); o[++t]=1;
		for(ll i=t-1;i;i--){
			for(ll j=0;j<o[i+1];j++) P[j]=Q[j];
			mul(P,P,P,o[i+1],o[i+1],o[i]);
			mul(a,P,P,o[i],o[i],o[i]);
			for(ll j=0;j<o[i];j++) Q[j]=(2*Q[j]-P[j]+mod)%mod;
		}
		for(ll i=0;i<o[1];i++) b[i]=Q[i];
	}
	void dao(ll *a,ll *b,ll n){
		for(ll i=1;i<n;i++) b[i-1]=a[i]*i%mod;
	}
	ll r=0;
	void jifen(ll *a,ll *b,ll n){
		while(r<n){
			++r;
			if(r>1) inv[r]=(mod-mod/r)*inv[mod%r]%mod;
			else inv[r]=1;
		}
		for(ll i=n-1;i>0;i--) b[i]=a[i-1]*inv[i]%mod;
		b[0]=0;
	}
	ll R[maxn];
	void ln(ll *a,ll *b,ll n){
		dao(a,R,n);
		Getinv(a,b,n);
		mul(b,R,R,n,n,n);
		jifen(R,b,n);
	}
	ll z[maxn],zlt,F[maxn],G[maxn];
	void Exp(ll *a,ll *b,ll n){
		zlt=0;
		for(ll i=0;i<n;i++) F[i]=0;
		while(n>1) z[++zlt]=n, n=n+1>>1;
		z[++zlt]=1; F[0]=1;
		for(ll i=zlt-1;i;i--){
			ln(F,G,z[i]);
			for(ll j=0;j<z[i];j++) G[j]=(a[j]<G[j]? a[j]+mod-G[j]:a[j]-G[j]);
			G[0]=(G[0]==mod-1? 0:G[0]+1);
			mul(F,G,F,z[i+1],z[i],z[i]);
		}
		for(ll i=0;i<z[1];i++) b[i]=F[i];
	}
	void Sqrt(ll *a,ll *b,ll n){
		zlt=0;
		for(ll i=0;i<n;i++) F[i]=0;
		while(n>1) z[++zlt]=n, n=n+1>>1;
		z[++zlt]=1; F[0]=1;
		for(ll i=zlt-1;i;i--){
			mul(F,F,G,z[i+1],z[i+1],z[i]);
			for(ll j=0;j<z[i];j++) G[j]=(G[j]+a[j]>=mod? G[j]+a[j]-mod:G[j]+a[j]);
			for(ll j=0;j<z[i+1];j++) F[j]=((F[j]<<1)>=mod? (F[j]<<1)-mod:F[j]<<1);
			Getinv(F,F,z[i]);
			mul(G,F,F,z[i],z[i],z[i]);
		}
		for(ll i=0;i<z[1];i++) b[i]=F[i];
	}
}D;

标签:frac,zlt,pmod,多项式,ll,ln,整理,模板
From: https://www.cnblogs.com/Sktn0089/p/18022061

相关文章

  • P8436 【模板】边双连通分量
    原题链接题解和点双连通分量不同在于点双联通分量:分量内任意两点之间至少有两条独立路径可走,两条路径所经过的点除了起点和终点都不同边双连通分量:分量内任意两点之间至少有两条独立路径可走,两条路径所经过的边都不同(包括重边)用这个图依然可以解释code#include<bits/stdc++......
  • P8435 【模板】点双连通分量
    原题链接题解唯一能解释的图片,黄色代表会执行入栈操作的点code#include<bits/stdc++.h>usingnamespacestd;intvis[500005]={0};intlow[500005]={0};stack<int>q;vector<int>ans[500005];vector<int>G[500005];intlen=0;intcnt=0;voidss(intnow,intf......
  • P3388 【模板】割点(割顶)
    原题链接题解先说结论对单个图做深度搜索树,对于树的根节点,它要能是割点当且仅当她有至少两个不互通的儿子节点对于树的非叶子非根节点,它要能是割点当且仅当存在儿子节点能去的时间戳最小的节点不小于当前节点的深度搜索序对于叶子节点,不可能成为割点code#include<bits/std......
  • JavaScript语法-字符串模板
    [TOC]##JavaScript模板字符串###代码以下是index.js的部分代码:```onShareAppMessage({const{toName,mainText,fromName}=this.data;debugger;return{title:'叮,您收到一张贺卡~',path:'pages/index/index?toname=${toName}&mai......
  • 多项式小寄
    多项式小记目录目录多项式小记目录序什么是多项式多项式四则运算加法减法乘法除法\(FFT\)多项式的点值表达\(DFT\)单位根算法原理核心流程代码\(IDFT\)结论证明代码最后的实现融融没用的常数优化蝴蝶变换递归变递推(迭代)三步变两步破除封建迷信最终代码\(NTT\)咋来的原根定义性......
  • C# 的布尔类型和字符串类型(模板字符串)
    //布尔类型bollboolb=false;b=1==1;//trueboolb1=1>23;//false//值类型:在代码中初始化类型的时候没有赋值但是系统会自动赋值的叫值类型//byteshortint(default0)longfloatdou......
  • 揭秘一线大厂Redis面试高频考点(3万字长文、吐血整理)
    ###3万+长文揭秘一线大厂Redis面试高频考点,整理不易,求一键三连:点赞、分享、收藏本文,已收录于,我的技术网站aijiangsir.com,有大厂完整面经,工作技术,架构师成长之路,等经验分享1、说说什么是Redis?Redis是一个开源的、基于内存的高性能键值对数据库,支持多种类型的数据结构,如字符......
  • 多项式初步
    多项式初步目录多项式初步自己写的分治FFT/NTTPart1分治FFT/NTTPart2①.多项式求逆:②.多项式带余除法:③.多项式开根:④.多项式对数:⑤.多项式exp:⑥.多项式快速幂:模板基础操作MTT自己写的分治FFT/NTTPart1给定序列\(g_{1\dotsn-1}\),求序列\(f_{0\dotsn-1}\)。其中......
  • U107394 拓扑排序模板
    原题链接在拓扑排序的基础上加上了一个条件:尽可能按字典序排序,这就使得题目难度加大。题解:拓扑排序+小根堆拓扑排序是采用队列一个一个出队列来删除对应结点的边,那么我们只需要保证每次出队列的结点都尽可能小,就能保证字典序。每次出队列的值都为队列中的最小值,刚好可以采用小......
  • 数学:多项式
    拉格朗日插值快速傅里叶变换(FFT)已经不知道被这玩意劝退了多少次了。但理解之后其实不算很阴间的东西?前置知识多项式负数单位根快速傅里叶变换快速傅里叶逆变换快速数论变换(NTT/FNTT)前置知识FFT注意到FFT的运算到处都是又\(\cos\)又\(\sin\)的,有不小的精度问题......