多项式求逆元模板【NTT/拆系数FFT】

版权声明:本文为博主原创文章,未经博主允许必须转载。 https://blog.csdn.net/C20181220_xiang_m_y/article/details/85288785

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
板题:

一. 洛谷4238

模998244353,NTT:

#include<cstdio>
#include<algorithm>
#define maxn 400005
#define LL long long
using namespace std;
const int mod = 998244353, G = 3;
LL wn,w;
inline LL ksm(LL a,LL b){
	LL s=1;
	for(;b;b>>=1,a=a*a%mod) if(b&1) s=s*a%mod;
	return s;
}
inline void change(LL *a,int len)
{
	for(int i=1,j=len/2,k;i<len-1;i++)
	{
		if(i<j) swap(a[i],a[j]);
		for(k=len/2;j>=k;j-=k,k>>=1);
		j+=k;
	}
}
inline void ntt(LL *a,int len,int flg)
{
	change(a,len);
	for(int i=2;i<=len;i<<=1)
	{
		if(flg==1) wn=ksm(G,(mod-1)/i);
		else wn=ksm(G,mod-1-(mod-1)/i);
		for(int j=0;j<len;j+=i)
		{
			w=1;
			for(int k=j;k<j+i/2;k++)
			{
				LL u=a[k],v=w*a[k+i/2]%mod;
				a[k]=(u+v)%mod,a[k+i/2]=(u-v+mod)%mod;
				w=w*wn%mod;
			}
		}
	}
	if(flg==-1){
		LL ni=ksm(len,mod-2);
		for(int i=0;i<len;i++) a[i]=a[i]*ni%mod;
	}
}
int n,len;
LL a[maxn],b[maxn],tmp[maxn];
inline void poly_inv(int n,LL *a,LL *b)
{
	if(n==1) {b[0]=ksm(a[0],mod-2);return;}
	poly_inv((n+1)>>1,a,b);
	len=1;while(len<n+n-1) len<<=1;
	for(int i=0;i<len;i++) tmp[i]=i<n?a[i]:0;
	ntt(tmp,len,1),ntt(b,len,1);
	for(int i=0;i<len;i++) {b[i]=(2-tmp[i]*b[i]%mod)*b[i]%mod;if(b[i]<0) b[i]+=mod;}
	ntt(b,len,-1);
	for(int i=n;i<len;i++) b[i]=0;
}
int main()
{
	scanf("%d",&n);
	for(int i=0;i<n;i++) scanf("%lld",&a[i]);
	poly_inv(n,a,b);
	for(int i=0;i<n;i++) printf("%lld%c",b[i],i==n-1?10:32);
}
二. 洛谷4239

模109+7,拆系数FFT(7次fft版本)

// luogu-judger-enable-o2
#include<cstdio>
#include<cmath>
#include<algorithm>
#define maxn 400005
#define LL long long
using namespace std;
const int mod = 1e9+7, M1 = 31623, M2 = 14122;
const double Pi = acos(-1);
struct complex
{
	double r,i;
	complex(double _r=0,double _i=0):r(_r),i(_i){}
	complex operator + (const complex &t)const{return complex(r+t.r,i+t.i);}
	complex operator - (const complex &t)const{return complex(r-t.r,i-t.i);}
	complex operator * (const complex &t)const{return complex(r*t.r-i*t.i,r*t.i+i*t.r);}
	complex conj(){return complex(r,-i);}
}w[20][maxn/2];
inline void change(complex *a,int len)
{
	for(int i=1,j=len/2,k;i<len-1;i++)
	{
		if(i<j) swap(a[i],a[j]);
		for(k=len/2;j>=k;j-=k,k>>=1);
		j+=k;
	}
}
inline void fft(complex *a,int len,int flg)
{
	change(a,len);
	for(int i=2,o=0;i<=len;i<<=1,o++)
		for(int j=0;j<len;j+=i)
			for(int k=j;k<j+i/2;k++)
			{
				complex u=a[k],v=(flg==1?w[o][k-j]:w[o][k-j].conj())*a[k+i/2];
				a[k]=u+v,a[k+i/2]=u-v;
			}
	if(flg==-1) for(int i=0;i<len;i++) a[i].r/=len;
}
inline void MTT(int *a,int *b,int n,int *ret)
{
	static complex A[maxn],B[maxn],C[maxn],D[maxn],rt[3][maxn];
	int len=1;while(len<n+n-1) len<<=1;
	for(int i=0;i<len;i++)
		if(i<n)
		{
			A[i]=a[i]/M1,B[i]=a[i]%M1;
			C[i]=b[i]/M1,D[i]=b[i]%M1;
		}
		else A[i]=B[i]=C[i]=D[i]=0;
	fft(A,len,1),fft(B,len,1),fft(C,len,1),fft(D,len,1);
	for(int i=0;i<len;i++) rt[2][i]=A[i]*C[i],rt[1][i]=A[i]*D[i]+B[i]*C[i],rt[0][i]=B[i]*D[i];
	fft(rt[0],len,-1),fft(rt[1],len,-1),fft(rt[2],len,-1);
	for(int i=0;i<n;i++) ret[i]=((llround(rt[0][i].r)%mod+llround(rt[1][i].r)*M1%mod)%mod+llround(rt[2][i].r)*M2%mod)%mod;
}
inline int ksm(int a,int b){
	int s=1;
	for(;b;b>>=1,a=1ll*a*a%mod) if(b&1) s=1ll*s*a%mod;
	return s;
}
int n,a[maxn],b[maxn],tmp[maxn];
inline void poly_inv(int n,int *a,int *b)
{
	if(n==1) {b[0]=ksm(a[0],mod-2);return;}
	poly_inv((n+1)>>1,a,b);
	MTT(a,b,n,tmp);
	MTT(b,tmp,n,tmp);
	for(int i=0;i<n;i++) b[i]=(2*b[i]%mod-tmp[i]+mod)%mod;
}
int main()
{
	scanf("%d",&n);int len=1;while(len<n+n-1) len<<=1;
	for(int i=2,o=0;i<=len;i<<=1,o++)
		for(int j=0;j<i/2;j++)
			w[o][j]=complex(cos(2*Pi*j/i),sin(2*Pi*j/i));
	for(int i=0;i<n;i++) scanf("%d",&a[i]);
	poly_inv(n,a,b);
	for(int i=0;i<n;i++) printf("%d%c",b[i],i==n-1?10:32);
}

FFT(4次fft版本)
算法解析可以看这两篇 \darr (膜拜大佬)
Miskcoo’s Space
Clin233

#include<cstdio>
#include<cmath>
#include<algorithm>
#define maxn 400005
#define LL long long
using namespace std;
const int mod = 1e9+7, M = (1<<15)-1;
const double Pi = acos(-1);
struct complex
{
	double r,i;
	complex(double _r=0,double _i=0):r(_r),i(_i){}
	complex operator + (const complex &t)const{return complex(r+t.r,i+t.i);}
	complex operator - (const complex &t)const{return complex(r-t.r,i-t.i);}
	complex operator * (const complex &t)const{return complex(r*t.r-i*t.i,r*t.i+i*t.r);}
	complex conj(){return complex(r,-i);}
}w[20][maxn/2];
inline void change(complex *a,int len)
{
	for(int i=1,j=len/2,k;i<len-1;i++)
	{
		if(i<j) swap(a[i],a[j]);
		for(k=len/2;j>=k;j-=k,k>>=1);
		j+=k;
	}
}
inline void fft(complex *a,int len,int flg)
{
	change(a,len);
	for(int i=2,o=0;i<=len;i<<=1,o++)
		for(int j=0;j<len;j+=i)
			for(int k=j;k<j+i/2;k++)
			{
				complex u=a[k],v=(flg==1?w[o][k-j]:w[o][k-j].conj())*a[k+i/2];
				a[k]=u+v,a[k+i/2]=u-v;
			}
	if(flg==-1) for(int i=0;i<len;i++) a[i].r/=len,a[i].i/=len;//注意这里的虚部也要除
}
inline void MTT(int *a,int *b,int n,int *ret)
{
	static complex A[maxn],B[maxn],rt[2][maxn],da,db,dc,dd;
	int len=1;while(len<n+n-1) len<<=1;
	for(int i=0;i<len;i++)
		if(i<n) A[i]=complex(a[i]>>15,a[i]&M),B[i]=complex(b[i]>>15,b[i]&M);
		else A[i]=B[i]=0;
	fft(A,len,1),fft(B,len,1);
	for(int i=0,j;i<len;i++)
	{
		j=(i==0?0:len-i);
		da=(A[i]+A[j].conj())*complex(0.5,0);
		db=(A[i]-A[j].conj())*complex(0,-0.5);
		dc=(B[i]+B[j].conj())*complex(0.5,0);
		dd=(B[i]-B[j].conj())*complex(0,-0.5);
		rt[0][i]=da*dc+db*dd*complex(0,1),rt[1][i]=db*dc+da*dd*complex(0,1);
	}
	fft(rt[0],len,-1),fft(rt[1],len,-1);
	for(int i=0;i<n;i++) ret[i]=((llround(rt[0][i].r)%mod<<30)+llround(rt[0][i].i)+((llround(rt[1][i].r)+llround(rt[1][i].i))%mod<<15))%mod;
}
inline int ksm(int a,int b){
	int s=1;
	for(;b;b>>=1,a=1ll*a*a%mod) if(b&1) s=1ll*s*a%mod;
	return s;
}
int n,a[maxn],b[maxn],tmp[maxn];
inline void poly_inv(int n,int *a,int *b)
{
	if(n==1) {b[0]=ksm(a[0],mod-2);return;}
	poly_inv((n+1)>>1,a,b);
	MTT(a,b,n,tmp);
	MTT(b,tmp,n,tmp);
	for(int i=0;i<n;i++) b[i]=(2*b[i]%mod-tmp[i]+mod)%mod;
}
int main()
{
	scanf("%d",&n);int len=1;while(len<n+n-1) len<<=1;
	for(int i=2,o=0;i<=len;i<<=1,o++)
		for(int j=0;j<i/2;j++)
			w[o][j]=complex(cos(2*Pi*j/i),sin(2*Pi*j/i));
	for(int i=0;i<n;i++) scanf("%d",&a[i]);
	poly_inv(n,a,b);
	for(int i=0;i<n;i++) printf("%d%c",b[i],i==n-1?10:32);
}

或者还有个优化版,change改成了用r[],预处理单位根改成O(n),空间小了很多

wlen=1;while(wlen<n+n-1) wlen<<=1;
for(int i=0;i<wlen;i++) w[i]=complex(cos(2*Pi*i/wlen),sin(2*Pi*i/wlen));
for(int i=0;i<len;i++) r[i]=(r[i>>1]>>1)|(i&1?len>>1:0);
int r[maxn],wlen;
inline void fft(complex *a,int len,int flg)
{
	for(int i=0;i<len;i++) if(i<r[i]) swap(a[i],a[r[i]]);
	for(int i=2;i<=len;i<<=1)
		for(int j=0,t=wlen/i;j<len;j+=i)//t=wlen/i
			for(int k=j,o=0;k<j+i/2;k++,o+=t)
			{
				complex u=a[k],v=(flg==1?w[o]:w[o].conj())*a[k+i/2];
				a[k]=u+v,a[k+i/2]=u-v;
			}
	if(flg==-1) for(int i=0;i<len;i++) a[i].r/=len,a[i].i/=len;//注意这里的虚部也要除
}

至于三模数NTT。。不想打。。而且效率也不高。。想看的请出门右转。。

猜你喜欢

转载自blog.csdn.net/C20181220_xiang_m_y/article/details/85288785