记录一些多项式代码

FFT

const double PI=acos(-1.0);
struct Complex
{
	double R,I;
	Complex(){}
	Complex(double _R,double _I)
	{
		R=_R;
		I=_I;
	}
};
Complex operator + (Complex x,Complex y)
{
	return Complex(x.R+y.R,x.I+y.I);
}
Complex operator - (Complex x,Complex y)
{
	return Complex(x.R-y.R,x.I-y.I);
}
Complex operator * (Complex x,Complex y)
{
	return Complex(x.R*y.R-x.I*y.I,x.R*y.I+x.I*y.R);
}

void FFT(Complex *a,int n,double type)
{
	for(int i=0,j=0;i<n;i++)
	{
		if(i<j)
		{
			swap(a[i],a[j]);
		}
		int k=n>>1;
		while(true)
		{
			j^=k;
			if(j>=k)
			{
				break;
			}
			else
			{
				k>>=1;
			}
		}
	}

	for(int m=1;m<n;m<<=1)
	{
		Complex w=Complex(cos(PI/m),sin(PI/m)*type);
		for(int k=0;k<n;k+=(m<<1))
		{
			Complex wi=Complex(1.0,0.0);
			for(int i=k;i<k+m;i++,wi=wi*w)
			{
				Complex t0=a[i],t1=a[i+m]*wi;
				a[i]=t0+t1;
				a[i+m]=t0-t1;
			}
		}
	}
	if(type==1)
	return;
	for(int i=0;i<n;i++)
	{
		a[i].R/=n;
		a[i].I/=n;
	}
}
Complex AA[MAXN],BB[MAXN];
int N;
void FFT(int n,int *a,int m,int *b,int *ans)
{
	N=1;
	for(int i=0;i<=n;i++)
	{
		AA[i].R=a[i];
	}
	for(int i=0;i<=m;i++)
	{
		BB[i].R=b[i];
	}
	while(N<=n+m)
	{
		N<<=1;
	}
	FFT(AA,N,1);
	FFT(BB,N,1);
	for(int i=0;i<=N;i++)
	{
		AA[i]=AA[i]*BB[i];
	}
	FFT(AA,N,-1);
	for(int i=0;i<=N;i++)
	{
		ans[i]=int(AA[i].R+0.5);
		AA[i].R=AA[i].I=BB[i].R=BB[i].I=0;
	}
}

\(n\)\(a\) 多项式最高次大小,\(m\)\(b\) 多项式最高次大小,\(ans\) 为答案多项式。

NTT

const int P=998244353,_3=332748118;
long long Pow(long long a,long long b)
{
	int ans=1;
	while(b)
	{
		if(b&1)
		ans=ans*a%P;
		a=a*a%P;
		b>>=1;
	}
	return ans; 
}
void NTT(long long *a,int n,int type)
{
	for(int i=0,j=0;i<n;i++)
	{
		if(i<j)
		{
			swap(a[i],a[j]);
		}
		int k=n>>1;
		while(true)
		{
			j^=k;
			if(j>=k)
			{
				break;
			}
			else
			{
				k>>=1;
			}
		}
	}

	for(int m=1;m<n;m<<=1)
	{
		long long w=Pow(type==1?3:_3,(P-1)/(m<<1));
		for(int k=0;k<n;k+=(m<<1))
		{
			long long wi=1;
			for(int i=k;i<k+m;i++,wi=wi*w%P)
			{
				long long t0=a[i],t1=a[i+m]*wi%P;
				a[i]=(t0+t1)%P;
				a[i+m]=(t0-t1+P)%P;
			}
		}
	}
	if(type==1)
	return;
	int _n=Pow(n,P-2);
	for(int i=0;i<n;i++)
	{
		a[i]=a[i]*_n%P;
	}
}
long long AA[MAXN],BB[MAXN];
int N;
void NTT(int n,int *a,int m,int *b,int *ans)
{
	memset(AA,0,sizeof(AA));
	memset(BB,0,sizeof(BB));
	N=1;
	for(int i=0;i<=n;i++)
	{
		AA[i]=a[i];
	}
	for(int i=0;i<=m;i++)
	{
		BB[i]=b[i];
	}
	while(N<=n+m)
	{
		N<<=1;
	}
	NTT(AA,N,1);
	NTT(BB,N,1);
	for(int i=0;i<=N;i++)
	{
		AA[i]=AA[i]*BB[i]%P;
	}
	NTT(AA,N,-1);
	for(int i=0;i<=N;i++)
	{
		ans[i]=AA[i];
	}
}

_3\(3\) 关于 \(P\) 的逆元,\(P\) 可以更改。用法同 FFT。

比较拉的全家桶。

#include <bits/stdc++.h>

using namespace std; 
const int Gen=3,P=998244353,MAXN=1e6+50;

void Add1(int &a,int b)
{
	a+=b;
	if(a>=P)
	a-=P;
}
int Add2(int a,int b)
{
	static int Sum;
	Sum=a+b;
	if(Sum>=P)
	return Sum-P;
	else
	return Sum;
}
void Sub1(int &a,int b)
{
	a-=b;
	if(a<0)
	a+=P;
}
int Sub2(int a,int b)
{
	static int Sum;
	Sum=a-b;
	if(Sum<0)
	return Sum+P;
	else
	return Sum;
}
void Mul1(int &a,int b)
{
	a=1ll*a*b%P;
}
int Mul2(int a,int b)
{
	return 1ll*a*b%P;
}
void CopyArray(int *a,int *b,int l,int r)
{
	for(int i=l;i<=r;i++)
	{
		a[i]=b[i];
	}
}
void ClearArray(int *a,int l,int r)
{
	for(int i=l;i<=r;i++)
	{
		a[i]=0;
	}
}
void AddArray(int *a,int *b,int l,int r)
{
	for(int i=l;i<=r;i++)
	{
		Add1(a[i],b[i]);
	}
}
void MulArray(int *a,int *b,int l,int r)
{
	for(int i=l;i<=r;i++)
	{
		Mul1(a[i],b[i]);
	}
}
void RevArray(int *a,int l,int r)
{
	static int b[MAXN];
	for(int i=l;i<=r;i++)
	{
		b[i]=a[i];
	}
	for(int i=l,j=r;i<=r;i++,j--)
	{
		a[i]=b[j];
		b[j]=0;
	}
}
int Pow(int a,int b=P-2)
{
	int ans=1;
	while(b)
	{
		if(b&1)
		{
			Mul1(ans,a);
		}
		Mul1(a,a);
		b>>=1;
	}
	return ans;
}
const int InvGen=Pow(Gen);
void NTT(int *a,int n,int type)
{
	for(int i=0,j=0;i<n;i++)
	{
		if(i<j)
		{
			swap(a[i],a[j]);
		}
		int k=n>>1;
		while(true)
		{
			j^=k;
			if(j>=k)
			{
				break;
			}
			else
			{
				k>>=1;
			}
		}
	}
	for(int m=1;m<n;m<<=1)
	{
		int w=Pow(type==1?3:InvGen,(P-1)/(m<<1));
		for(int k=0;k<n;k+=(m<<1))
		{
			int wi=1;
			for(int i=k;i<k+m;i++,Mul1(wi,w))
			{
				int t0=a[i],t1=Mul2(a[i+m],wi);
				a[i]=Add2(t0,t1);
				a[i+m]=Sub2(t0,t1);
			}
		}
	}
	if(type==1)
	return;
	int _n=Pow(n);
	for(int i=0;i<n;i++)
	{
		Mul1(a[i],_n);
	}
}

void MulPoly(int lim,int *a,int *b,int Mod=1e9)
{
	static int BB[MAXN];
	NTT(a,lim,1);
	CopyArray(BB,b,0,lim);
	NTT(BB,lim,1);
	MulArray(a,BB,0,lim);
	NTT(a,lim,-1);
	ClearArray(a,Mod+1,lim);
	ClearArray(BB,0,lim);
}
void MulPoly(int n,int *a,int m,int *b,int Mod=1e9)
{
	static int BB[MAXN];
	int lim=1;
	while(lim<=n+m)
	{
		lim<<=1;
	}
	NTT(a,lim,1);
	CopyArray(BB,b,0,m);
	NTT(BB,lim,1);
	MulArray(a,BB,0,lim);
	NTT(a,lim,-1);
	ClearArray(a,Mod+1,lim);
	ClearArray(BB,0,lim);
}
void InvPoly(int n,int *a)
{
	static int AA[MAXN],BB[MAXN],ans[MAXN];
	ans[0]=Pow(a[0],P-2);
	int len,N;
	for(len=1;len<=(n<<1);len<<=1)
	{
		N=len<<1;
		CopyArray(AA,a,0,len-1);
		CopyArray(BB,ans,0,len-1);
		NTT(AA,N,1);
		NTT(BB,N,1);
		for(int i=0;i<=N;i++)
		{
			ans[i]=Mul2(Sub2(2,Mul2(AA[i],BB[i])),BB[i]);
		}
		NTT(ans,N,-1);
		ClearArray(ans,len,N);
	}
	ClearArray(AA,0,len);
	ClearArray(BB,0,len);
	CopyArray(a,ans,0,n);
	ClearArray(ans,0,len);
}
void DivPoly(int n,int *a,int m,int *b)
{
	static int AA[MAXN],BB[MAXN];
  	int Len=n-m;
  	RevArray(b,0,m);
  	CopyArray(AA,b,0,Len);
  	RevArray(b,0,m);
  	RevArray(a,0,n);
  	CopyArray(BB,a,0,Len);
  	RevArray(a,0,n);
  	InvPoly(Len,AA);
	MulPoly(Len,AA,Len,BB);
	RevArray(AA,0,Len);
  	MulPoly(m,b,Len,AA);
	for(int i=0;i<m;i++)
  	{
  		b[i]=(a[i]-b[i]+P)%P;
	}	
  	ClearArray(b,m,m+Len);
  	CopyArray(a,AA,0,Len);
	ClearArray(a,Len+1,n);
}
void DaoPoly(int n,int *a)
{
	for(int i=1;i<n;i++)
	{
		a[i-1]=Mul2(a[i],i);
	}
	a[n]=0;
}
int Inv[MAXN];
void Init(int n)
{
  	Inv[1]=1;
  	for(int i=2;i<=n;i++)
  	{
		Inv[i]=Mul2(Inv[P%i],P-P/i);
 	}
}
void JiPoly(int n,int *a)
{
  	for(int i=n;i>=1;i--)
  	{
  		a[i]=Mul2(a[i-1],Inv[i]);
  	}
  a[0]=0;
}
void LnPoly(int n,int *a)
{
  static int AA[MAXN];
  CopyArray(AA,a,0,n);
  InvPoly(n,AA);
  DaoPoly(n,a);
  MulPoly(n,a,n,AA,n);
  JiPoly(n-1,a);
  ClearArray(AA,0,n);
}

void ExpPoly(int n,int *a)
{
	static int AA[MAXN],ans[MAXN];
	ans[0]=1;
	int len=2,N=1;
	while(N<=n)
	{
		N<<=1;
	}
	for(;len<=N;len<<=1)
	{
		CopyArray(AA,ans,0,len>>1);
		LnPoly(len,AA);
		for(int i=0;i<len;i++)
		{
			AA[i]=Sub2(a[i],AA[i]);
		}
		Add1(AA[0],1);
		MulPoly(len,ans,len,AA,len<<1);
		
		ClearArray(ans,len,len<<1);
		ClearArray(AA,len,len<<1);
	}
	ClearArray(AA,0,len);
	CopyArray(a,ans,0,n);
	ClearArray(ans,0,len);
}
/*
void ModPoly(int n,int *a,int m,int *b)
{
	int Invb=Pow(b[m],P-2);
	for(int i=n;i>=m;i--)
	{
		int Shang=Mul2(a[i],Invb);
		for(int j=i,k=m;j>=i-m;j--,k--)
		{
			Sub1(a[j],Mul2(b[k],Shang));
		}
	}
}
*/

void ModPoly(int n,int *a,int m,int *b)
{
	static int AA[MAXN],BB[MAXN],CC[MAXN];
  	int Len=n-m;
  	RevArray(b,0,m);
  	CopyArray(AA,b,0,Len);
  	RevArray(b,0,m);
  	RevArray(a,0,n);
  	CopyArray(BB,a,0,Len);
  	RevArray(a,0,n);
  	InvPoly(Len,AA);
	MulPoly(Len,AA,Len,BB);
	RevArray(AA,0,Len);
	CopyArray(CC,b,0,m);
  	MulPoly(m,CC,Len,AA);
	for(int i=0;i<m;i++)
  	{
  		Sub1(a[i],CC[i]);
	}	
	ClearArray(a,m,n);
	ClearArray(CC,0,n);
	ClearArray(AA,0,Len<<1);
	ClearArray(BB,0,Len<<1);
}
int F[20][MAXN<<2];
vector<int>Vec[MAXN<<1];
int tot,Root;
int ls[MAXN<<1],rs[MAXN<<1];
void Solve1(int &u,int l,int r,int *X) 
{
	static int A[MAXN<<2],B[MAXN<<2],C[MAXN<<2];
	u=++tot;
	int Len=1;
	while(Len<=(r-l+1))
	{
		Len<<=1;
	}
	Vec[u].resize(Len);
	if(l==r) 
	{
		Vec[u][0]=X[l]?Sub2(P,X[l]):0; 
		Vec[u][1]=1; 
		return; 
	}
	int Mid=l+r>>1;
	Solve1(ls[u],l,Mid,X); 
	Solve1(rs[u],Mid+1,r,X);
	int Size=Vec[ls[u]].size();
	for(int i=0;i<Size;i++)
	{
		A[i]=Vec[ls[u]][i]; 
	}
	ClearArray(A,Size,Len);
	Size=Vec[rs[u]].size();
	for(int i=0;i<Size;i++)
	{
		B[i]=Vec[rs[u]][i];	
	} 
	ClearArray(B,Size,Len);
	MulPoly(Len,A,B);
	for(int i=0;i<Len;i++)
	{
		Vec[u][i]=A[i];
	}
	ClearArray(A,0,Len);
	ClearArray(B,0,Len);
}
int G[MAXN<<2];
void Solve2(int depth,int u,int l,int r,int n,int *ans,int *X) 
{
	int Len=r-l+1;
	for(int i=0;i<=Len;i++)
	{
		G[i]=Vec[u][i];
	}
	CopyArray(F[depth],F[depth-1],0,max(n,Len));
	if(n>=Len)
	{
		ModPoly(n,F[depth],Len,G);
	}
	ClearArray(G,0,Len);
	if(Len<=400) 
	{
    	for (int i=l;i<=r;i++)
		{
	      	int Now=1;
	      	for (int j=0;j<=min(n,Len);j++)
			{
				Add1(ans[i],Mul2(Now,F[depth][j]));
	        	Mul1(Now,X[i]);
	      	}
    	}
		return;
	}
	int Mid=l+r>>1;
	depth++;
	Solve2(depth,ls[u],l,Mid,Len-1,ans,X);
	Solve2(depth,rs[u],Mid+1,r,Len-1,ans,X);
}

void DuoDianQiuZhi(int n,int *a,int m,int *X,int *ans)
{
	for(int i=0;i<=n;i++) 
	{
		F[0][i]=a[i];
	}
	for(int i=0;i<=m;i++)
	{
		G[i]=Vec[Root][i];
	}
	Solve2(1,Root,1,m,n,ans,X);
}
int DeltaDao[MAXN],ans[MAXN];
int HH[20][MAXN<<2];
void FenZhiNTT2(int depth,int u,int l,int r,int *Y)
{
	static int AA[MAXN],BB[MAXN];
	if(l==r)
	{
		HH[depth][0]=Y[l];
		return;
	}
	int Mid=l+r>>1;
	int Size;
	FenZhiNTT2(depth+1,ls[u],l,Mid,Y);
	Size=Vec[rs[u]].size();
	for(int i=0;i<Size;i++)
	{
		AA[i]=Vec[rs[u]][i];
	}
	CopyArray(HH[depth],HH[depth+1],0,Mid-l+1);
	ClearArray(HH[depth+1],0,Mid-l+1);
	MulPoly(Mid-l+1,HH[depth],Size,AA);
	ClearArray(AA,0,Size);
	FenZhiNTT2(depth+1,rs[u],Mid+1,r,Y);
	Size=Vec[ls[u]].size();
	for(int i=0;i<Size;i++)
	{
		AA[i]=Vec[ls[u]][i];
	}
	CopyArray(BB,HH[depth+1],0,r-Mid);
	ClearArray(HH[depth+1],0,r-Mid);
	MulPoly(r-Mid,BB,Size,AA);
	AddArray(HH[depth],BB,0,r-l+1);
	ClearArray(AA,0,r-l+1);
	ClearArray(BB,0,r-l+1);
}

void FastLag(int n,int *x,int *y,int *ans)
{
	Solve1(Root,1,n,x);
	int Size=Vec[Root].size();
	for(int i=0;i<Size;i++)
	{
		DeltaDao[i]=Vec[Root][i];
	}
	DaoPoly(Size,DeltaDao);
	DuoDianQiuZhi(n,DeltaDao,n,x,ans);
	for(int i=1;i<=n;i++)
	{
		Mul1(y[i],Pow(ans[i]));
	}
	FenZhiNTT2(1,Root,1,n,y);
	for(int i=0;i<=n-1;i++)
	{
		ans[i]=(HH[1][i]%P+P)%P;
	}
}
int main() 
{
	
}
posted @ 2022-06-28 20:39  0htoAi  阅读(69)  评论(2编辑  收藏  举报