Loading

萌新的多项式学习笔记(板子)

萌新的多项式学习笔记(板子)

详细讲解

FFT

直接放板子

struct cp{
	double x,y;
	cp(double xx=0,double yy=0){x=xx,y=yy;}
};
int r[maxn];
cp operator + (const cp &a,const cp &b){return cp(a.x+b.x,a.y+b.y);}
cp operator - (const cp &a,const cp &b){return cp(a.x-b.x,a.y-b.y);}
cp operator * (const cp &a,const cp &b){return cp(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);}
cp operator * (const cp &a,double b){return cp(a.x*b,a.y*b);}
const double Pi=acos(-1.0);
void fft(cp *a,int N,int op){
	for(int i=0;i<N;i++)if(i<r[i])swap(a[i],a[r[i]]);
	for(int i=1;i<N;i<<=1){
		cp wn=cp(cos(Pi/i),op*sin(Pi/i));
		for(int j=0;j<N;j+=i<<1){
			cp w=cp(1,0);
			for(int k=0;k<i;k++,w=w*wn){
				cp x=a[j+k],y=w*a[j+k+i];
				a[j+k]=x+y;a[j+k+i]=x-y;
			}
		}
	}
}
#define lbt(x) ((x)&-(x))
void work(cp *a,cp *b,cp *c,int M){
	int N=M;
	while(N>lbt(N))N+=lbt(N);
	int l=__lg(N);
	for(int i=0;i<N;i++)r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));

	fft(a,N,1);
	fft(b,N,1);
	for(int i=0;i<N;i++)c[i]=a[i]*b[i];
	fft(c,N,-1);
	for(int i=0;i<N;i++)c[i].x=(int)(c[i].x/N+0.5);
}

NTT

\(10^9+7\) 不是 NTT 模数。

其余所有模数大多都可以取 \(3189\) 作为原根。

直接放板子

int ksm(int a,int b){
	int ans=1;
	for(;b;b>>=1,a=a*a%mod)if(b&1)ans=ans*a%mod;
	return ans;
}
#define lbt(x) ((x)&-(x))
const int g=3189;
void ntt(int *a,int N,int op){
	for(int i=0;i<N;i++)if(i<r[i])swap(a[i],a[r[i]]);
	for(int i=1;i<N;i<<=1){
		int wn=ksm(g,(mod-1)/(i<<1));
		if(op==-1)wn=ksm(wn,mod-2);
		for(int j=0;j<N;j+=(i<<1)){
			int w=1,x,y;
			for(int k=j;k<j+i;k++,w=w*wn%mod){
				x=a[k],y=w*a[k+i]%mod;
				a[k]=(x+y)%mod;
				a[k+i]=(x-y+mod)%mod;
			}
		}
	}
}
void work(int *a,int *b,int *c,int M){
	int N=M;
	while(N!=lbt(N))N+=lbt(N);
	int l=__lg(N);
	for(int i=0;i<N;i++)r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));

	memset(c,0,sizeof(int)*N);

	ntt(a,N,1);
	ntt(b,N,1);
	for(int i=0;i<=N;i++)c[i]=a[i]*b[i]%mod;
	ntt(c,N,-1);
	int inv=ksm(N,mod-2);
	for(int i=0;i<=M;i++)c[i]=c[i]*inv%mod;

	memset(a,0,sizeof(int)*N);
	memset(b,0,sizeof(int)*N);
}
posted @ 2024-02-02 10:26  洛谷Augury  阅读(11)  评论(0编辑  收藏  举报