【学习笔记】多项式求逆

求:

\[A(x)B(x)\equiv 1(\bmod x^n). \]

解:

若已知\(A(x)B'(x)\equiv 1(\bmod x^\frac{n}{2}):\)

\[A(x)B(x)\equiv 1(\bmod x^\frac{n}{2}) \]

同时减去:

\[B(x)-B'(x)\equiv 0(\bmod x^\frac{n}{2}) \]

两边平方:

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

同乘以\(A(x):\)

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

\(A(x)B(x)\equiv 1(\bmod x^n):\)

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

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

由此即可递归求解。复杂度\(O(n\log n).\)

#include<bits/stdc++.h>
using namespace std;
const int mod=998244353;
const int N=2100000;
const int g=3;
int rev[N],a[N],b[N],c[N],n;
inline int add(int x,int y){return (x+y)%mod;}
inline int mul(int x,int y){return 1ll*x*y%mod;}
inline int qpow(int x,int y){
	int res=1;
	while(y){
		if(y&1)res=mul(res,x);
		x=mul(x,x);y>>=1;
	}
	return res;
}
void NTT(int *a,int n,int x){
	for(int i=0;i<n;++i)if(i<rev[i])swap(a[i],a[rev[i]]);
	for(int i=1;i<n;i<<=1){
		int gn=qpow(g,(mod-1)/(i<<1));
		for(int j=0;j<n;j+=(i<<1)){
			int G=1,x,y;
			for(int k=0;k<i;++k,G=mul(G,gn)){
				x=a[j+k],y=mul(G,a[i+j+k]);
				a[j+k]=add(x,y);a[i+j+k]=add(x,mod-y);
			}
		}
	}
	if(x==1)return;
	int inv=qpow(n,mod-2);reverse(a+1,a+n);
	for(int i=0;i<n;++i)a[i]=mul(a[i],inv);
}
void Getinv(int d,int *a,int *b){
	if(d==1){b[0]=qpow(a[0],mod-2);return;}
	Getinv((d+1)>>1,a,b);
	int lim=1,len=0;
	while(lim<(d<<1))lim<<=1,++len;
	for(int i=1;i<lim;++i)rev[i]=(rev[i>>1]>>1)|((i&1)<<(len-1));
	for(int i=0;i<d;++i)c[i]=a[i];
	for(int i=d;i<lim;++i)c[i]=0;
	NTT(c,lim,1);NTT(b,lim,1);
	for(int i=0;i<lim;++i)b[i]=1LL*(2-1LL*c[i]*b[i]%mod+mod)%mod*b[i]%mod;
	NTT(b,lim,-1);
	for(int i=d;i<lim;++i)b[i]=0;
}
int main(){
	scanf("%d",&n);
	for(int i=0;i<n;++i)scanf("%d",&a[i]);
	Getinv(n,a,b);
	for(int i=0;i<n;++i)printf("%d ",b[i]); 
	return 0;
}

例题:分治\(FFT\)

解:设\(f,g\)的生成函数\((g_0=0)\)

\[F(x)=\sum_{i=0}^\infty f_ix_i,G(x)=\sum_{i=0}^\infty g_ix^i \]

\[F(x)*G(x)=\sum_{k=0}^\infty \sum_{i=0}^k f_ig_{k-i} \]

\[=(\sum_{k=0}^\infty f_k)-f_0x^0 \]

\[=F(x)-f_0 \]

因为我们只需要前\(n-1\)项,所以我们可以直接在\(\bmod x^n\)意义下进行。

于是:

\[F(x)G(x)\equiv F(x)-f_0(\bmod x^n) \]

\[F(x)(G(x)-1)\equiv -f_0(\bmod x^n) \]

\[F(x)\equiv -\frac{f_0}{G(x)-1}(\bmod x^n) \]

\[F(x)\equiv \frac{f_0}{1-G(x)}(\bmod x^n) \]

于是,直接对\(1-G(x)\)进行求逆即可。

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mod=998244353;
const int g=3;
const int N=500010;
int a[N],b[N],c[N],rev[N],n;
inline int add(int x,int y){return (x+y+mod)%mod;}
inline int mul(int x,int y){return 1ll*x*y%mod;}
inline int qpow(int x,int y){
	int res=1;
	while(y){
		if(y&1)res=mul(res,x);
		x=mul(x,x);y>>=1;
	}
	return res;
}
void NTT(int *a,int n,int x){
	for(int i=0;i<n;++i)if(i<rev[i])swap(a[i],a[rev[i]]);
	for(int i=1;i<n;i<<=1){
		int gn=qpow(g,(mod-1)/(i<<1));
		for(int j=0;j<n;j+=(i<<1)){
			int G=1,x,y;
			for(int k=0;k<i;++k,G=mul(G,gn)){
				x=a[j+k],y=mul(G,a[i+j+k]);
				a[j+k]=add(x,y);a[i+j+k]=add(x,mod-y);
			}
		}
	}
	if(x==1)return;
	int inv=qpow(n,mod-2);reverse(a+1,a+n);
	for(int i=0;i<n;++i)a[i]=mul(a[i],inv);
}
void Getinv(int d,int *a,int *b){
	if(d==1){b[0]=qpow(a[0],mod-2);return;}
	Getinv((d+1)>>1,a,b);
	int lim=1,len=0;
	while(lim<(d<<1))lim<<=1,++len;
	for(int i=1;i<lim;++i)rev[i]=(rev[i>>1]>>1)|((i&1)<<(len-1));
	for(int i=0;i<d;++i)c[i]=a[i];
	for(int i=d;i<lim;++i)c[i]=0;
	NTT(c,lim,1);NTT(b,lim,1);
	for(int i=0;i<lim;++i)b[i]=1LL*(2-1ll*c[i]*b[i]%mod+mod)%mod*b[i]%mod;
	NTT(b,lim,-1);
	for(int i=d;i<lim;++i)b[i]=0;
}
signed main(){
	scanf("%lld",&n);
	for(int i=1;i<n;++i)scanf("%lld",&a[i]);a[0]=1;
	for(int i=1;i<n;++i)a[i]%=mod,a[i]=mod-a[i];
	Getinv(n,a,b);
	for(int i=0;i<n;++i)printf("%lld ",b[i]);
	return 0;
}
posted @ 2020-08-13 16:58  Refined_heart  阅读(180)  评论(0编辑  收藏  举报