【模板】多项式

FFT

FFT模板(正常)
//Author:RingweEH
//P3803 【模板】多项式乘法(FFT)
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#define ll long long
#define db double
using namespace std;
int min( int a,int b ) { return (a<b) ? a : b; }
int max( int a,int b ) { return (a>b) ? a : b; }
void bmin( int &a,int b ) { a=(a<b) ? a : b; }
void bmax( int &a,int b ) { a=(a>b) ? a : b; }
int read()
{
	int x=0; char ch=getchar();
	while ( ch>'9' || ch<'0' ) ch=getchar();
	while ( ch<='9' && ch>='0' ) x=x*10+ch-48,ch=getchar();
	return x;
}

const int N=2100000;
const db PI=acos(-1.0)*2;
int n,m,rev[N];
struct Complex
{
	db x,y;
	Complex( db _x=0,db _y=0 ) : x(_x),y(_y) {}
}F[N],G[N];
Complex operator + ( Complex t1,Complex t2 ) { return Complex(t1.x+t2.x,t1.y+t2.y); }
Complex operator - ( Complex t1,Complex t2 ) { return Complex(t1.x-t2.x,t1.y-t2.y); }
Complex operator * ( Complex t1,Complex t2 ) { return Complex(t1.x*t2.x-t1.y*t2.y,t1.x*t2.y+t1.y*t2.x); }

void FFT( int lim,Complex *f,bool fl )
{
	int i,k,len,l;
	for ( i=0; i<lim; i++ ) if ( i<rev[i] ) swap( f[i],f[rev[i]] );
	for ( k=2,len; k<=lim; k<<=1 )
	{
		len=k>>1; Complex w(cos(PI/k),sin(PI/k));
		if ( !fl ) w.y*=-1;
		for ( i=0; i<lim; i+=k )
		{
			Complex buf(1,0);
			for ( l=i; l<i+len; l++ )
			{
				Complex tmp=buf*f[len+l];
				f[len+l]=f[l]-tmp; f[l]=f[l]+tmp; 
				buf=buf*w;
			}
		}
	}
}

int main()
{
	n=read(); m=read(); int i;
	for ( i=0; i<=n; i++ ) F[i].x=read();
	for ( i=0; i<=m; i++ ) G[i].x=read();
	
	int lim=1; for ( ; lim<=(n+m); lim<<=1 );
	for ( i=0; i<lim; i++ ) rev[i]=(rev[i>>1]>>1)|((i&1) ? lim>>1 : 0);
	FFT( lim,F,1 ); FFT( lim,G,1 );		//DFT
	for ( i=0; i<lim; i++ ) F[i]=F[i]*G[i];
	FFT( lim,F,0 );						//IDFT
	for ( i=0; i<=n+m; i++ ) printf( "%d ",(int)(F[i].x/lim+0.49) );

	return 0;
}
FFT模板(三变二)
//Author:RingweEH
//P3803 【模板】多项式乘法(FFT)
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#define ll long long
#define db double
using namespace std;
int min( int a,int b ) { return (a<b) ? a : b; }
int max( int a,int b ) { return (a>b) ? a : b; }
void bmin( int &a,int b ) { a=(a<b) ? a : b; }
void bmax( int &a,int b ) { a=(a>b) ? a : b; }
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin),p1==p2)?EOF:*p1++)
char buf[1<<20],*p1=buf,*p2=buf;
int read()
{
	int x=0; char ch=getchar();
	while ( ch>'9' || ch<'0' ) ch=getchar();
	while ( ch<='9' && ch>='0' ) x=x*10+ch-48,ch=getchar();
	return x;
}
void write( int x ) { if(x<0) putchar(45); if ( x>9 ) write(x/10); putchar(x%10+48); }
const int N=2100000;
const db PI=acos(-1.0)*2;
int n,m,rev[N];
struct Complex
{
	db x,y;
	Complex( db _x=0,db _y=0 ) : x(_x),y(_y) {}
}F[N];//,G[N];
Complex operator + ( Complex t1,Complex t2 ) { return Complex(t1.x+t2.x,t1.y+t2.y); }
Complex operator - ( Complex t1,Complex t2 ) { return Complex(t1.x-t2.x,t1.y-t2.y); }
Complex operator * ( Complex t1,Complex t2 ) { return Complex(t1.x*t2.x-t1.y*t2.y,t1.x*t2.y+t1.y*t2.x); }

void FFT( Complex *f,bool fl )
{
	int i,k,len,l;
	for ( i=0; i<n; i++ ) 
		if ( i<rev[i] ) swap( f[i],f[rev[i]] );
	for ( k=2,len; k<=n; k<<=1 )
	{
		len=k>>1; Complex w(cos(PI/k),sin(PI/k));
		if ( !fl ) w.y*=-1;
		for ( i=0; i<n; i+=k )
		{
			Complex buf(1,0);
			for ( l=i; l<i+len; l++ )
			{
				Complex tmp=buf*f[len+l];
				f[len+l]=f[l]-tmp; f[l]=f[l]+tmp;
				buf=buf*w;
			}
		}
	}
}

int main()
{
	n=read(); m=read(); int i;
	for ( i=0; i<=n; i++ ) F[i].x=read();
	for ( i=0; i<=m; i++ ) F[i].y=read();
	
	for ( m+=n,n=1; n<=m; n<<=1 );
	for ( i=0; i<n; i++ ) rev[i]=(rev[i>>1]>>1)|((i&1) ? n>>1 : 0);
	FFT( F,1 ); //FFT( G,1 );		//DFT
	for ( i=0; i<n; i++ ) F[i]=F[i]*F[i];
	FFT( F,0 );						//IDFT
	for ( i=0; i<=m; i++ )
		write((int)(F[i].y/n/2+0.49)),putchar(32);
		//printf( "%d ",(int)(F[i].y/n/2+0.49) ); //printf( "%d ",(int)(F[i].x/n+0.49) );

	return 0;
}

NTT

NTT
//Author:RingweEH
//P3803 【模板】多项式乘法(FFT)
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#define ll long long
#define db double
using namespace std;
int min( int a,int b ) { return (a<b) ? a : b; }
int max( int a,int b ) { return (a>b) ? a : b; }
void bmin( int &a,int b ) { a=(a<b) ? a : b; }
void bmax( int &a,int b ) { a=(a>b) ? a : b; }
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin),p1==p2)?EOF:*p1++)
char buf[1<<20],*p1=buf,*p2=buf;
int read()
{
	int x=0; char ch=getchar();
	while ( ch>'9' || ch<'0' ) ch=getchar();
	while ( ch<='9' && ch>='0' ) x=x*10+ch-48,ch=getchar();
	return x;
}
void write( int x ) { if(x<0) putchar(45); if ( x>9 ) write(x/10); putchar(x%10+48); }
void swap( ll &a,ll &b ) { a^=b; b^=a; a^=b; }

const int N=2100000;
const ll Mod=998244353,G=3,InvG=332748118;
int n,m,rev[N];
ll f[N],g[N],Invn;

ll power( ll a,ll b=Mod-2 )
{
	ll res=1;
	for ( ; b; b>>=1,a=a*a%Mod )
		if ( b&1 ) res=res*a%Mod;
	return res;
}

void NTT( ll *f,bool fl )
{
	int i,k,len,l;
	for ( i=0; i<n; i++ ) 
		if ( i<rev[i] ) swap( f[i],f[rev[i]] );
	for ( k=2; k<=n; k<<=1 )
	{
		len=k>>1; ll nwG=power( fl ? G : InvG,(Mod-1)/k );
		for ( i=0; i<n; i+=k )
		{
			ll buf=1;
			for ( l=i; l<i+len; l++ )
			{
				ll tmp=buf*f[len+l]%Mod;
				f[len+l]=f[l]-tmp; 
				if ( f[len+l]<0 ) f[len+l]+=Mod;
				f[l]=f[l]+tmp;
				if ( f[l]>=Mod ) f[l]-=Mod;
				buf=buf*nwG%Mod;
			}
		}
	}
}

int main()
{
	n=read(); m=read(); int i;
	for ( i=0; i<=n; i++ ) f[i]=read();
	for ( i=0; i<=m; i++ ) g[i]=read();
	
	for ( m+=n,n=1; n<=m; n<<=1 );
	for ( i=0; i<n; i++ ) rev[i]=(rev[i>>1]>>1)|((i&1) ? n>>1 : 0);
	NTT( f,1 ); NTT( g,1 );	
	for ( i=0; i<n; i++ ) f[i]=f[i]*g[i]%Mod;
	NTT( f,0 );	Invn=power(n);
	for ( i=0; i<=m; i++ )
		write((int)(f[i]*Invn%Mod)),putchar(32);

	return 0;
}
分治FFT
//Author: RingweEH
//P4721 【模板】分治FFT
#include <cstdio>
#include <cstring>
#include <algorithm>
#define ll long long
#define db double
using namespace std;
int min( int a,int b ) { return a<b ? a : b; }
int max( int a,int b ) { return a>b ? a : b; }
void bmax( int &a,int b ) { a=(a>b) ? a : b; }
void bmin( int &a,int b ) { a=(a<b) ? a : b; }
void swap( int &a,int &b ) { a^=b; b^=a; a^=b; }
inline int read()
{
    int x=0; char ch=getchar();
    while ( ch>'9' || ch<'0' ) ch=getchar();
    while ( ch<='9' && ch>='0' ) x=x*10+ch-48,ch=getchar();
    return x;
}
#define Mod 998244353
const int N=1e5+10,M=4e5+10;
namespace Math
{
	int inv[N];//,fac[N],infac[N];
	int power( int a,int b ) { int res=1; for (;b;b>>=1,a=1ll*a*a%Mod) if (b&1) res=1ll*a*res%Mod; return res; }
	inline void bmod( int &x ) { x-=Mod; x+=x>>31&Mod; }
};
using Math :: power;
using Math :: bmod;
namespace Poly
{
#define Clear(a,n) memset(a,0,sizeof(int)*n)
#define Copy(a,b,n) memcpy(a,b,sizeof(int)*n)
#define Rev(a,b) reverse(a,b)

int rev[M],rt[M],lim,lg,lasn;	//反转数组,原根,上界的值和log
void Poly_Init( int n ) 
{
	if ( n==lasn ) return; lasn=n; int i,j,w;
	for ( lg=0,lim=1; lim<n; lg++,lim<<=1 );
	for ( i=0; i<lim; i++ ) rev[i]=(rev[i>>1]>>1) | ((i&1)<<(lg-1));
	for ( i=1; i<lim; i<<=1 )
	{
		w=power(3,(Mod-1)/(i<<1)); rt[i]=1;
		for ( j=1; j<i; j++ ) rt[i+j]=1ll*rt[i+j-1]*w%Mod;
	}
}
void NTT( int *f,int opt )
{
	int i,j,k,invn,len,t1,t2;
	for ( i=0; i<lim; i++ ) if ( i>rev[i] ) swap( f[i],f[rev[i]] );
	for ( i=1; i<lim; i<<=1 )
		for ( j=0; j<lim; j+=i<<1 )
			for ( k=0; k<i; k++ )
			{
				t1=f[j+k]; t2=1ll*rt[i+k]*f[i+j+k]%Mod;
				bmod(f[j+k]=t1+t2); bmod(f[i+j+k]=t1+Mod-t2);
			}
	if ( opt ) return; invn=power(lim,Mod-2);
	for ( i=0; i<lim; i++ ) f[i]=1ll*f[i]*invn%Mod;
}
void Poly_InitPart( int n )
{
	if ( n==lasn ) return; lasn=n; int i,j,w;
	for ( lg=0,lim=1; lim<n; lg++,lim<<=1 );
	for ( i=0; i<lim; i++ ) rev[i]=(rev[i>>1]>>1) | ((i&1)<<(lg-1));
}
};
using Poly :: NTT;
using Poly :: Poly_Init;
using Poly :: Poly_InitPart;
int n,F[M],G[M],ans[M],H[M];

void CDQ_NTT( int l,int r )
{
	if ( l+1>=r ) return;
	int mid=(l+r)>>1,len=r-l,i; CDQ_NTT(l,mid);
	Poly_InitPart(len);
	for ( i=0; i<len; i++ ) G[i]=H[i];
	for ( i=l; i<mid; i++ ) F[i-l]=ans[i];
	for ( i=mid; i<r; i++ ) F[i-l]=0;
	NTT( F,1 ); NTT( G,1 );
	for ( int i=0; i<len; i++ ) F[i]=1ll*F[i]*G[i]%Mod;
	reverse(F+1,F+len); NTT( F,0 );
	for ( i=mid; i<r; i++ ) bmod(ans[i]+=F[i-l]);
	CDQ_NTT(mid,r);
}

int main()
{
	n=read();
	for ( int i=1; i<n; i++ ) H[i]=read();
	Poly_Init(n); ans[0]=1; CDQ_NTT(0,Poly::lim);
	for ( int i=0; i<n; i++ ) printf( "%d ",ans[i] );

	return 0;
}
任意模数NTT
//Author: RingweEH
#include <cstdio>
#include <cstring>
#include <algorithm>
#define ll long long
#define db double
using namespace std;
int min( int a,int b ) { return a<b ? a : b; }
int max( int a,int b ) { return a>b ? a : b; }
void bmax( int &a,int b ) { a=(a>b) ? a : b; }
void bmin( int &a,int b ) { a=(a<b) ? a : b; }
int read()
{
    int x=0,w=1; char ch=getchar();
    while ( ch>'9' || ch<'0' ) { if ( ch=='-' ) w=-1; ch=getchar(); }
    while ( ch<='9' && ch>='0' ) x=x*10+ch-'0',ch=getchar();
    return x*w;
}

inline int power( int a,int b,int Mod ) { int res=1; for (;b;b>>=1,a=1ll*a*a%Mod) if (b&1) res=1ll*a*res%Mod; return res; }
inline int Get_Inv( int x,int Mod ) { return power(x,Mod-2,Mod); }
inline int pmod( int x,int Mod ) { return x+=x>>31&Mod; }
const int Mod1=998244353,Mod2=1004535809,Mod3=469762049,Gn=3,M=4e5+10;
const ll Mod12=1ll*Mod1*Mod2;
const int Inv1=Get_Inv(Mod1,Mod2),Inv2=Get_Inv(Mod12%Mod3,Mod3);
int Mod;
struct ModInt
{
	int x1,x2,x3;
	ModInt( int _x1=0,int _x2=0,int _x3=0 ) : x1(_x1),x2(_x2),x3(_x3) {}
	ModInt operator + ( ModInt t ) 
	{ return ModInt( pmod(x1+t.x1-Mod1,Mod1),pmod(x2+t.x2-Mod2,Mod2),pmod(x3+t.x3-Mod3,Mod3) ); }
	ModInt operator - ( ModInt t ) 
	{ return ModInt( pmod(x1-t.x1,Mod1),pmod(x2-t.x2,Mod2),pmod(x3-t.x3,Mod3) ); }
	ModInt operator * ( ModInt t ) 
	{ return ModInt( 1ll*x1*t.x1%Mod1,1ll*x2*t.x2%Mod2,1ll*x3*t.x3%Mod3 ); }
	int Merge()
	{
		ll t1=1ll*(x2-x1+Mod2)%Mod2*Inv1%Mod2*Mod1+x1;
		ll t2=(x3-t1%Mod3+Mod3)%Mod3; t2=t2*Inv2%Mod3*(Mod12%Mod)%Mod; t2=t2+t1%Mod; t2%=Mod;
		return t2;
	}
}rt[M];
int lim,Lg,rev[M];
void Poly_Init( int n )
{
	for (lim=1,Lg=0 ; lim<=n; lim<<=1,Lg++ );
	for ( int i=0; i<lim; i++ ) rev[i]=(rev[i>>1]>>1) | ((i&1)<<(Lg-1));
	for ( int i=1; i<lim; i<<=1 )
	{
		ModInt nw(power(Gn,(Mod1-1)/(i<<1),Mod1),power(Gn,(Mod2-1)/(i<<1),Mod2),
			power(Gn,(Mod3-1)/(i<<1),Mod3));
		rt[i]=ModInt(1,1,1);
		for ( int j=1; j<i; j++ ) rt[i+j]=rt[i+j-1]*nw;
	}
}

void NTT( ModInt *f,int opt )
{
	int i,j,k,len; ModInt t1,t2;
	for ( i=0; i<lim; i++ ) if ( i>rev[i] ) swap( f[i],f[rev[i]] );
	for ( i=1; i<lim; i<<=1 )
		for ( j=0; j<lim; j+=i<<1 )
			for ( k=0; k<i; k++ )
			{
				t1=f[j+k]; t2=rt[i+k]*f[i+j+k];
				f[j+k]=t1+t2; f[i+j+k]=t1-t2;
			}	if ( opt ) return; 
	ModInt invn=ModInt(Get_Inv(lim,Mod1),Get_Inv(lim,Mod2),Get_Inv(lim,Mod3));
	for ( i=0; i<lim; i++ ) f[i]=f[i]*invn;
}

int n,m;
ModInt F[M],G[M];

int main()
{
	n=read(); m=read(); Mod=read(); n++; m++;
	for ( int i=0,x; i<n; i++ ) x=read()%Mod,F[i]=ModInt(x,x,x);
	for ( int i=0,x; i<m; i++ ) x=read()%Mod,G[i]=ModInt(x,x,x);
	Poly_Init( n+m ); NTT( F,1 ); NTT( G,1 );
	for ( int i=0; i<lim; i++ ) F[i]=F[i]*G[i];
	reverse(F+1,F+lim);  NTT( F,0 );
	for ( int i=0; i<n+m-1; i++ ) 
		printf( "%d ",F[i].Merge() ); 

	return 0;
}

FWT

FWT模板
//Author: RingweEH
#include <cstdio>
#include <cstring>
#include <algorithm>
#define ll long long
#define db double
using namespace std;
int min( int a,int b ) { return a<b ? a : b; }
int max( int a,int b ) { return a>b ? a : b; }
void bmax( int &a,int b ) { a=(a>b) ? a : b; }
void bmin( int &a,int b ) { a=(a<b) ? a : b; }
int read()
{
    int x=0,w=1; char ch=getchar();
    while ( ch>'9' || ch<'0' ) { if ( ch=='-' ) w=-1; ch=getchar(); }
    while ( ch<='9' && ch>='0' ) x=x*10+ch-'0',ch=getchar();
    return x*w;
}

const int N=5e5+10,Mod=998244353,Inv2=499122177;
inline int bmod( int x ) { return x+=x>>31&Mod; }
int lim,F[N],G[N],n,ans[N];

void FWT_Or( int *f,int opt )
{
	int i,j,k,len;
	for ( i=2; i<lim; i<<=1 )
		for ( len=(i>>1),j=0; j<lim; j+=i )
			for ( k=j; k<j+len; k++ )
				(f[k+len]+=bmod(1ll*f[k]*opt%Mod))%=Mod;
}
void FWT_And( int *f,int opt )
{
	int i,j,k,len;
	for ( i=2; i<lim; i<<=1 )
		for ( len=(i>>1),j=0; j<lim; j+=i )
			for ( k=j; k<j+len; k++ )
				(f[k]+=bmod(1ll*f[k+len]*opt))%=Mod;
}
void FWT_Xor( int *f,int opt )
{
	int i,j,k,len;
	for ( i=2; i<lim; i<<=1 )
		for ( len=i>>1,j=0; j<lim; j+=i )
			for ( k=j; k<j+len; k++ )
			{
				int t1=f[k],t2=f[k+len];
				f[k]=(t1+t2)%Mod; f[k+len]=(t1+Mod-t2)%Mod;
				if ( opt==-1 ) f[k]=1ll*f[k]*Inv2%Mod,f[k+len]=1ll*f[k+len]*Inv2%Mod;
			}
}
void Poly_Mul( int n,int *f,int *g,int *res,int opt )
{
	for ( lim=1; lim<=n; lim<<=1 );
	static int tf[N],tg[N];
	memcpy( tf,f,sizeof(int)*n ); memcpy( tg,g,sizeof(int)*n );
	memset( tf+n,0,sizeof(int)*(lim-n) ); memset( tg+n,0,sizeof(int)*(lim-n) );
	if ( opt==0 )
	{
		FWT_Or( tf,1 ); FWT_Or( tg,1 );
		for ( int i=0; i<lim; i++ ) tf[i]=1ll*tf[i]*tg[i]%Mod;
		FWT_Or( tf,-1 );
		memcpy( res,tf,sizeof(int)*n ); memset( res+n,0,sizeof(int)*(lim-n) );
		return;
	}
	else if ( opt==1 )
	{
		FWT_And( tf,1 ); FWT_And( tg,1 );
		for ( int i=0; i<lim; i++ ) tf[i]=1ll*tf[i]*tg[i]%Mod;
		FWT_And( tf,-1 );
		memcpy( res,tf,sizeof(int)*n ); memset( res+n,0,sizeof(int)*(lim-n) );
		return;
	}
	else if ( opt==2 )
	{
		FWT_Xor( tf,1 ); FWT_Xor( tg,1 );
		for ( int i=0; i<lim; i++ ) tf[i]=1ll*tf[i]*tg[i]%Mod;
		FWT_Xor( tf,-1 );
		memcpy( res,tf,sizeof(int)*n ); memset( res+n,0,sizeof(int)*(lim-n) );
		return;
	}
}

int main()
{
	n=read(); n=1<<n;
	for ( int i=0; i<n; i++ ) F[i]=read();
	for ( int i=0; i<n; i++ ) G[i]=read();
	Poly_Mul( n,F,G,ans,0 );
	for ( int i=0; i<n; i++ ) printf( "%d ",ans[i] ); puts("");
	Poly_Mul( n,F,G,ans,1 );
	for ( int i=0; i<n; i++ ) printf( "%d ",ans[i] ); puts("");
	Poly_Mul( n,F,G,ans,2 );
	for ( int i=0; i<n; i++ ) printf( "%d ",ans[i] ); puts("");

	return 0;
}

多项式全家桶

多项式全家桶
//Author: RingweEH
#include <cstdio>
#include <cstring>
#include <algorithm>
#define ll long long
#define db double
using namespace std;
int min( int a,int b ) { return a<b ? a : b; }
int max( int a,int b ) { return a>b ? a : b; }
void bmax( int &a,int b ) { a=(a>b) ? a : b; }
void bmin( int &a,int b ) { a=(a<b) ? a : b; }
void swap( int &a,int &b ) { a^=b; b^=a; a^=b; }
inline int read()
{
    int x=0; char ch=getchar();
    while ( ch>'9' || ch<'0' ) ch=getchar();
    while ( ch<='9' && ch>='0' ) x=x*10+ch-48,ch=getchar();
    return x;
}
#define Mod 998244353
inline int readMod()
{
    ll x=0; char ch=getchar();
    while ( ch>'9' || ch<'0' ) ch=getchar();
    while ( ch<='9' && ch>='0' ) x=(x*10ll+ch-48)%Mod,ch=getchar();
    return (int)x;
}
const int N=1e5+10,M=4e5+10;
namespace Math
{
	int inv[N];//,fac[N],infac[N];
	int power( int a,int b ) { int res=1; for (;b;b>>=1,a=1ll*a*a%Mod) if (b&1) res=1ll*a*res%Mod; return res; }
	inline void bmod( int &x ) { x-=Mod; x+=x>>31&Mod; }
	void Init( int n=N-1 )
	{
	 	inv[1]=1; for ( int i=2; i<=n; i++ ) inv[i]=1ll*inv[Mod%i]*(Mod-Mod/i)%Mod;
	 	//fac[0]=1; for ( int i=1; i<=n; i++ ) fac[i]=1ll*i*fac[i-1]%Mod;
	 	//infac[n]=power(fac[n],Mod-2); for ( int i=n-1; i>=0; i-- ) infac[i]=1ll*(i+1)*infac[i+1]%Mod;
	}
};
using Math :: power;
using Math :: bmod;
namespace Poly
{
#define Clear(a,n) memset(a,0,sizeof(int)*(n))
#define Copy(a,b,n) memcpy(a,b,sizeof(int)*(n))
#define Rev(a,b) reverse(a,b)

int rev[M],rt[M],lim,lg,lasn;	//反转数组,原根,上界的值和log
void Poly_Init( int n ) 
{
	if ( n==lasn ) return; lasn=n; int i,j,w;
	for ( lg=0,lim=1; lim<=n; lg++,lim<<=1 );
	for ( i=0; i<lim; i++ ) rev[i]=(rev[i>>1]>>1) | ((i&1)<<(lg-1));
	for ( i=1; i<lim; i<<=1 )
	{
		w=power(3,(Mod-1)/(i<<1)); rt[i]=1;
		for ( j=1; j<i; j++ ) rt[i+j]=1ll*rt[i+j-1]*w%Mod;
	}
}
void NTT( int *f,int opt )
{
	int i,j,k,invn,len,t1,t2;
	for ( i=0; i<lim; i++ ) if ( i>rev[i] ) swap( f[i],f[rev[i]] );
	for ( i=1; i<lim; i<<=1 )
		for ( j=0; j<lim; j+=i<<1 )
			for ( k=0; k<i; k++ )
			{
				t1=f[j+k]; t2=1ll*rt[i+k]*f[i+j+k]%Mod;
				bmod(f[j+k]=t1+t2); bmod(f[i+j+k]=t1+Mod-t2);
			}
	if ( opt ) return; invn=power(lim,Mod-2);
	for ( i=0; i<lim; i++ ) f[i]=1ll*f[i]*invn%Mod;
}
void Poly_Mul( int n,int m,int *f,int *g,int *res )
{
	Poly_Init(n+m); static int tf[M],tg[M];
	Copy(tf,f,n); Clear(tf+n,lim-n); NTT(tf,1); 
	Copy(tg,g,m); Clear(tg+m,lim-m); NTT(tg,1);
 	for ( int i=0; i<lim; i++ ) tf[i]=1ll*tf[i]*tg[i]%Mod;
 	Rev(tf+1,tf+lim); NTT(tf,0); Copy(res,tf,n+m-1);
}
void Poly_Inv( int n,int *f,int *g )
{	//G(x)\equiv 2H(x)-H(x)^2F(x)(\bmod x^n)
	static int tf[M];
	if ( n==1 ) { g[0]=power(f[0],Mod-2); return; }
	Poly_Inv((n+1)>>1,f,g); Poly_Init(n<<1);
	Copy(tf,f,n); Clear(tf+n,lim-n); Clear(g+n,lim-n); NTT(tf,1); NTT(g,1);
	for ( int i=0; i<lim; i++ ) g[i]=1ll*g[i]*(2+Mod-1ll*g[i]*tf[i]%Mod)%Mod;
	Rev(g+1,g+lim); NTT(g,0); Clear(g+n,lim-n);
}
void Itg( int n,int *f,int *g ) //Intergral
{
	for ( int i=1; i<=n; i++ ) g[i]=1ll*f[i-1]*Math::inv[i]%Mod; g[0]=0;
}
void Drv( int n,int *f,int *g ) //Derivative
{
	for ( int i=0; i<n-1; i++ ) g[i]=1ll*(i+1)*f[i+1]%Mod; g[n-1]=0;
}
void Poly_ln( int n,int *f,int *g )
{
	static int tf[M],tg[M];
	Drv(n,f,tf); Clear(tg,n); Poly_Inv(n,f,tg); 
	Poly_Mul(n,n,tf,tg,tf);  Itg(n,tf,g);
}
void Poly_Exp( int n,int *f,int *g )
{	//G(x)=H(x)(1-\ln(H(x))+A(x))
	if ( n==1 ) { g[0]=1; return; } static int tf[M];
	Poly_Exp( (n+1)>>1,f,g ); Clear(tf,n); Poly_ln(n,g,tf); tf[0]--;
	for ( int i=0; i<n; i++ ) bmod( tf[i]=f[i]+Mod-tf[i] );
	Poly_Mul(n,n,g,tf,g); Clear(g+n,lim-n);
}
void Poly_Sqrt( int powe,int *f,int *g )
{//F(x)=\dfrac{H(x)^2+A(x)}{2H(x)}
	if ( powe==1 ) { g[0]=1; return; }
	static int tf[M]; Poly_Sqrt((powe+1)>>1,f,g);
	Clear(tf,powe); Poly_Inv(powe,g,tf); Poly_Mul(powe,powe,tf,f,tf);
	int inv2=power(2,Mod-2); for ( int i=0; i<powe; i++ ) g[i]=1ll*(g[i]+tf[i])*inv2%Mod;
}
void Poly_Power( int n,int k,int *f,int *g )
{
	static int tf[M]; Clear(tf,n); Poly_ln(n,f,tf);
	for ( int i=0; i<n; i++ ) tf[i]=1ll*tf[i]*k%Mod;
	Poly_Exp(n,tf,g);
}
void Poly_DivMod( int n,int m,int *f,int *g,int *q,int *r )
{	//F^R(x)\equiv G^R(x)Q^R(x)\pmod {x^{n-m+1}}
	static int tf[M],tg[M],nw[M];
	Copy(tf,f,n); Copy(tg,g,m); Rev(tf,tf+n); Rev(tg,tg+m);
	for ( int i=n-m+1; i<(n<<1); i++ ) tg[i]=0;
	Poly_Inv(n-m+1,tg,nw); Poly_Mul(n,n-m+1,tf,nw,q);
	for ( int i=n-m+1; i<(n<<1); i++ ) q[i]=0; 
	Rev(q,q+n-m+1); Poly_Mul(n-m+1,m,q,g,r);
}
};

int main()
{
//freopen( "exam.in","r",stdin );

	return 0;
}
多项式多点求值
//-------------------多点求值---------------------
#define lc (pos<<1)
#define rc (pos<<1|1)
int GMod[N<<6],*arr=GMod,*Evg[M];
void Eval_Mul( int n,int m,int *f,int *g,int *res )  //Evaluation
{
	static int tf[M],tg[M]; Poly_Init(n);
	Copy(tf,f,n); Clear(tf+n,lim-n); NTT( tf,1 );
	Copy(tg,g,m); Clear(tg+m,lim-m); NTT( tg,1 );
	for ( int i=0; i<lim; i++ ) tf[i]=1ll*tf[i]*tg[i]%Mod;
	reverse( tf+1,tf+lim ); NTT( tf,0 ); Copy( res,tf+m-1,n-m+1 );
}
void Eval_Pre( int l,int r,int pos,int *f )
{
	Evg[pos]=arr; arr+=r-l+1;
	if ( r-l==1 ) { Evg[pos][0]=Mod-f[l],Evg[pos][1]=1; return; }
	int mid=(l+r)>>1;
	Eval_Pre( l,mid,lc,f ); Eval_Pre( mid,r,rc,f );
	Poly_Mul( mid-l+1,r-mid+1,Evg[lc],Evg[rc],Evg[pos] );
}
void Eval_Sol( int l,int r,int pos,int *f,int *g )
{
	if ( r-l==1 ) { g[l]=f[0]; return; }
	int mid=(l+r)>>1,*fl,*fr;
	fl=arr; arr+=mid-l; fr=arr; arr+=r-mid;
	Eval_Mul( r-l,r-mid+1,f,Evg[rc],fl ); 
	Eval_Mul( r-l,mid-l+1,f,Evg[lc],fr );
	Eval_Sol( l,mid,lc,fl,g ); Eval_Sol( mid,r,rc,fr,g );
}
void Poly_Eval( int n,int m,int *a,int *f,int *g )
{
	static int t[M]; n=max( n,m );
	Eval_Pre( 0,n,1,a ); reverse( Evg[1],Evg[1]+n+1 );
	Poly_Inv( n,Evg[1],t ); reverse( t,t+n );
	Poly_Mul( n,n,t,f,t ); Copy( t,t+n,n );
	Eval_Sol( 0,n,1,t,g );
	for ( int i=0; i<m; i++ ) bmod( g[i]=1ll*g[i]*a[i]%Mod+f[0] );
	for ( int i=m; i<n; i++ ) g[i]=0;
}
多项式快速插值
//Author: RingweEH
#define Mod 998244353
const int N=1e5+10,M=4e5+10;
int power( int a,int b ) { int res=1; for (;b;b>>=1,a=1ll*a*a%Mod) if (b&1) res=1ll*a*res%Mod; return res; }
inline int bmod( int x ) { x-=Mod; x+=x>>31&Mod; return x; }

namespace Poly
{
void Poly_Mod( int n,int m,int *f,int *g,int *r )
{	//F^R(x)\equiv G^R(x)Q^R(x)\pmod {x^{n-m+1}}
	static int tf[M],tg[M],nw[M],q[M]; Poly_Init(n+m);
	Copy(tf,f,n); Copy(tg,g,m); Rev(tf,tf+n); Rev(tg,tg+m);
	for ( int i=n-m+1; i<(n<<1); i++ ) tg[i]=0;
	Poly_Inv(n-m+1,tg,nw); Poly_Mul(n,n-m+1,tf,nw,q);
	for ( int i=n-m+1; i<(n<<1); i++ ) q[i]=0; 
	Rev(q,q+n-m+1); Copy(nw,g,m); Poly_Mul(n-m+1,m,q,nw,r);
	for ( int i=0; i<m-1; i++ ) r[i]=bmod(f[i]-r[i]+Mod);
}
};
using namespace Poly;
#define lc pos<<1
#define rc pos<<1|1
int x[N],y[N],*F[M],n,H[M],v[M];
int *Evg[M],len[M];
void Prework( int l,int r,int pos )
{
	if ( l==r ) { len[pos]=2; Evg[pos]=new int[2]; Evg[pos][0]=Mod-x[l]; Evg[pos][1]=1; return; }
	static int t[M]; int mid=(l+r)>>1;
	Prework(l,mid,lc); Prework(mid+1,r,rc);
	len[pos]=len[lc]+len[rc]-1; Evg[pos]=new int[len[pos]];
	Poly_Mul( len[lc],len[rc],Evg[lc],Evg[rc],t );
	for ( int i=0; i<len[pos]; i++ ) Evg[pos][i]=t[i];
}
void Solve( int l,int r,int pos,int *f )
{
	if ( l==r ) { v[l]=f[0]; return; }
	int t[len[pos]<<1]; int mid=(l+r)>>1; memset(t,0,sizeof(t));
	Poly_Mod( len[pos]-1,len[lc],f,Evg[lc],t ); 
	Solve( l,mid,lc,t );
	Poly_Mod( len[pos]-1,len[rc],f,Evg[rc],t ); 
	Solve( mid+1,r,rc,t );
}
void Merge( int l,int r,int pos )
{
	if ( l==r ) { F[pos]=new int[2]; F[pos][0]=v[l]; F[pos][1]=0;  return; }
	static int fl[M],fr[M]; int mid=(l+r)>>1;
	Merge( l,mid,lc ); Merge( mid+1,r,rc );
	Poly_Mul( len[lc],len[rc],F[lc],Evg[rc],fl );
	Poly_Mul( len[rc],len[lc],F[rc],Evg[lc],fr );
	F[pos]=new int[len[pos]];
	for ( int i=0; i<len[pos]; i++ ) F[pos][i]=bmod(fl[i]+fr[i]);
}

signed main()
{
	n=read();
	for ( int i=1; i<=n; i++ ) x[i]=read(),y[i]=read();

	Prework(1,n,1); 
	Drv( len[1],Evg[1],H );
	Solve( 1,n,1,H );
	for ( int i=1; i<=n; i++ ) v[i]=1ll*power(v[i],Mod-2)*y[i]%Mod;
	Merge( 1,n,1 );
	for ( int i=0; i<n; i++ ) printf( "%d ",F[1][i] );

	return 0;
}
多项式三角函数
const int TriI=86583718,Inv2=power(2,Mod-2),InvI=power(TriI,Mod-2);
void Poly_SinCos( int n,int *f,int *g,int opt )	//0:sin,1:cos
{
	Poly_Init(n); static int tf[M];
	Copy(tf,f,n); Clear(tf+n,lim-n);
	for ( int i=0; i<n; i++ ) tf[i]=1ll*tf[i]*TriI%Mod;
	Poly_Exp( n,tf,g ); Clear(tf,lim); Poly_Inv( n,g,tf );	//g:exp(if(x)),tf:exp(-if(x))
	if ( !opt )
	{
		for ( int i=0; i<n; i++ ) bmod(g[i]+=Mod-tf[i]);
		int cons=1ll*Inv2*InvI%Mod;
		for ( int i=0; i<n; i++ ) g[i]=1ll*g[i]*cons%Mod;
		Clear(g+n,lim-n);
	}
	else
	{
		for ( int i=0; i<n; i++ ) bmod(g[i]+=tf[i]);
		for ( int i=0; i<n; i++ ) g[i]=1ll*g[i]*Inv2%Mod;
		Clear(g+n,lim-n);
	}
}
posted @ 2020-11-12 13:48  MontesquieuE  阅读(38)  评论(0编辑  收藏  举报