• 多项式


    • 并没有讲解.只是记录用.

    (FFT)

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    const int MAXN=4e6+10;
    inline int read()
    {
    	int x=0;
    	bool pos=1;
    	char ch=getchar();
    	for(; !isdigit(ch); ch=getchar())
    		if(ch=='-')
    			pos=0;
    	for(; isdigit(ch); ch=getchar())
    		x=x*10+ch-'0';
    	return pos?x:-x;
    }
    struct cp
    {
    	double x,y;
    	cp(double xx=0,double yy=0)
    	{
    		x=xx;
    		y=yy;
    	}
    	cp operator +(const cp &b) const
    	{
    		return cp(x+b.x,y+b.y);
    	}
    	cp operator -(const cp &b) const
    	{
    		return cp(x-b.x,y-b.y);
    	}
    	cp operator *(const cp &b) const
    	{
    		return cp(x*b.x-y*b.y,x*b.y+y*b.x);
    	}
    };
    const double PI=acos(-1.0);
    int rev[MAXN];
    void init(int n,int lim)
    {
    	for(int i=0; i<n; ++i)
    	{
    		for(int j=0; j<lim; ++j)
    			if((i>>j)&1)
    				rev[i]|=1<<(lim-j-1);
    	}
    }
    void FFT(cp *a,int n,bool invflag)
    {
    	for(int i=0; i<n; ++i)
    	{
    		if(i<rev[i])
    			swap(a[i],a[rev[i]]);
    	}
    	for(int l=2; l<=n; l<<=1)
    	{
    		int m=l>>1;
    		cp wi=cp(cos(2*PI/l),sin(2*PI/l));
    		if(invflag)
    			wi=cp(cos(2*PI/l),-sin(2*PI/l));
    		for(cp *p=a; p!=a+n; p+=l)
    		{
    			cp w=cp(1,0);
    			for(int i=0; i<m; ++i)
    			{
    				cp t=w*p[i+m];
    				p[i+m]=p[i]-t;
    				p[i]=p[i]+t;
    				w=w*wi;
    			}
    		}
    	}
    	if(invflag)
    	{
    		for(int i=0; i<n; ++i)
    			a[i].x/=n,a[i].y/=n;
    	}
    }
    int n,m;
    cp a[MAXN],b[MAXN];
    int main()
    {
    	n=read(),m=read();
    	++n,++m;
    	for(int i=0; i<n; ++i)
    		a[i]=cp((double)read(),0);
    	for(int i=0; i<m; ++i)
    		b[i]=cp((double)read(),0);
    	int N=1,lim=0;
    	while(N<n+m-1)
    		N<<=1,++lim;
    	init(N,lim);
    	FFT(a,N,false);
    	FFT(b,N,false);
    	for(int i=0; i<N; ++i)
    		a[i]=a[i]*b[i];
    	FFT(a,N,true);
    	for(int i=0; i<n+m-1; ++i)
    		printf("%d ",(int)(a[i].x+0.5));
    	return 0;
    }
    

    (NTT)

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    const int MAXN=4e6+10;
    inline int read()
    {
    	int x=0;
    	bool pos=1;
    	char ch=getchar();
    	for(; !isdigit(ch); ch=getchar())
    		if(ch=='-')
    			pos=0;
    	for(; isdigit(ch); ch=getchar())
    		x=x*10+ch-'0';
    	return pos?x:-x;
    }
    const int P=998244353,G=3;
    int add(int a,int b)
    {
    	return (a + b) % P;
    }
    int mul(int a,int b)
    {
    	return 1LL * a * b % P;
    }
    int fpow(int a,int b)
    {
    	int res=1;
    	while(b)
    	{
    		if(b&1)
    			res=mul(res,a);
    		a=mul(a,a);
    		b>>=1;
    	}
    	return res;
    }
    int inv(int x)
    {
    	return fpow(x,P-2);
    }
    int rev[MAXN];
    void init(int n,int lim)
    {
    	for(int i=0; i<n; ++i)
    	{
    		for(int j=0; j<lim; ++j)
    			if((i>>j)&1)
    				rev[i]|=1<<(lim-j-1);
    	}
    }
    void NTT(int *a,int n,bool invflag)
    {
    	for(int i=0; i<n; ++i)
    	{
    		if(i<rev[i])
    			swap(a[i],a[rev[i]]);
    	}
    	for(int l=2; l<=n; l<<=1)
    	{
    		int gi=fpow(G,(P-1)/l);
    		if(invflag)
    			gi=inv(gi);
    		int m=l>>1;
    		for(int *p=a;p!=a+n;p+=l)
    		{
    			int g=1;
    			for(int i=0; i<m; ++i)
    			{
    				int t=mul(g,p[i+m]);
    				p[i+m]=add(p[i],P-t);
    				p[i]=add(p[i],t);
    				g=mul(g,gi);
    			}
    		}
    	}
    	if(invflag)
    	{
    		int Invn=inv(n);
    		for(int i=0; i<n; ++i)
    			a[i]=mul(a[i],Invn);
    	}
    }
    int n,m;
    int a[MAXN],b[MAXN];
    int main()
    {
    	n=read(),m=read();
    	++n,++m;
    	for(int i=0; i<n; ++i)
    		a[i]=read();
    	for(int i=0; i<m; ++i)
    		b[i]=read();
    	int N=1,lim=0;
    	while(N<n+m-1)
    		N<<=1,++lim;
    	init(N,lim);
    	NTT(a,N,false);
    	NTT(b,N,false);
    	for(int i=0; i<N; ++i)
    		a[i]=mul(a[i],b[i]);
    	NTT(a,N,true);
    	for(int i=0; i<n+m-1; ++i)
    		printf("%d ",a[i]);
    	return 0;
    }
    

    (FWT)

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    inline int read()
    {
    	int out=0,fh=1;
    	char jp=getchar();
    	while ((jp>'9'||jp<'0')&&jp!='-')
    		jp=getchar();
    	if (jp=='-')
    		fh=-1,jp=getchar();
    	while (jp>='0'&&jp<='9')
    		out=out*10+jp-'0',jp=getchar();
    	return out*fh;
    }
    const int P=998244353,inv2=(P+1)>>1;
    inline int add(int a,int b)
    {
    	return (a + b) % P;
    }
    inline int mul(int a,int b)
    {
    	return 1LL * a * b % P;
    }
    void FWT(int *a,int n,int op)
    {
    	for(int l=2;l<=n;l<<=1)
    	{
    		int m=l>>1;
    		for(int *p=a;p!=a+n;p+=l)
    			for(int i=0;i<m;++i)
    			{
    				int x0=p[i],x1=p[i+m];
    				if(op==1)//or
    					p[i]=x0,p[i+m]=add(x0,x1);
    				else if(op==2)//and
    					p[i]=add(x0,x1),p[i+m]=x1;
    				else//xor
    					p[i]=add(x0,x1),p[i+m]=add(x0,P-x1);
    			}
    	}
    }
    void IFWT(int *a,int n,int op)
    {
    	for(int l=2;l<=n;l<<=1)
    	{
    		int m=l>>1;
    		for(int *p=a;p!=a+n;p+=l)
    			for(int i=0;i<m;++i)
    			{
    				int x0=p[i],x1=p[i+m];
    				if(op==1)
    					p[i]=x0,p[i+m]=add(x1,P-x0);
    				else if(op==2)
    					p[i]=add(x0,P-x1),p[i+m]=x1;
    				else
    					p[i]=mul(add(x0,x1),inv2),p[i+m]=mul(add(x0,P-x1),inv2);
    			}
    	}
    }
    const int MAXN=(1<<17)+10;
    int a[MAXN],b[MAXN],c[MAXN];
    int main()
    {
    	int n=read();
    	n=1<<n;
    	for(int i=0;i<n;++i)
    		a[i]=read();
    	for(int i=0;i<n;++i)
    		b[i]=read();
    	for(int op=1;op<=3;++op)
    	{
    		FWT(a,n,op);
    		FWT(b,n,op);
    		for(int i=0;i<n;++i)
    			c[i]=mul(a[i],b[i]);
    		IFWT(a,n,op);
    		IFWT(b,n,op);
    		IFWT(c,n,op);
    		for(int i=0;i<n;++i)
    			printf("%d ",c[i]);
    		puts("");
    	}
    	return 0;
    }
    

    三模数 (NTT)

    • 取三个具有 (P=pcdot 2^k+1) 形式的模数,在每个模意义下分别求解,最后用 (CRT​) 合并.这样做要求最终答案不超过三个模数之积.

    拆系数 (FFT)

    • 对任意模数 (P) ,记 (m=sqrt P).那么把每个系数写成 (a imes m+b,a,b<m) 的形式,然后乘法分配律分别做,这样每个系数都不会超过 (P) ,最后再合并.

    分治 (NTT/FFT)

    • 现在要算这样一个形式的卷积:

    [f_i=sum_{j=1}^{i}f_{i-j}cdot g_j ]

    • 给出初始值 (f_0) 以及 (g) 的所有值,求 (f) 的所有项.
    • 如果每次直接做 (NTT/FFT) ,复杂度显然为 (O(n^2logn)) ,爆炸.
    • 考虑一个像 (cdq) 分治的东西,即算左边,再算左边对右边的贡献,再算右边,长度为 (1) 时返回.
    • 若当前计算区间 ([l,r)) ,就把 (f) 的前 (frac {r-l} 2) 项与 (g) 的前 (r-l) 项做卷积,把答案的后 (frac {r-l} 2) 项加入 (f) 的对应位置.
    • 这样做后半段一定是对的,所以就不用关注长度的问题了.时间复杂度为 (O(nlog^2n)) .

    分治 (NTT)

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    inline ll read()
    {
        ll out=0,fh=1;
        char jp=getchar();
        while ((jp>'9'||jp<'0')&&jp!='-')
            jp=getchar();
        if (jp=='-')
            fh=-1,jp=getchar();
        while (jp>='0'&&jp<='9')
            out=out*10+jp-'0',jp=getchar();
        return out*fh;
    }
    const int P=998244353,G=3;
    inline int add(int a,int b)
    {
    	return (a + b) % P;
    }
    inline int mul(int a,int b)
    {
    	return 1LL * a * b % P;
    }
    int fpow(int a,int b)
    {
    	int res=1;
    	while(b)
    	{
    		if(b&1)
    			res=mul(res,a);
    		a=mul(a,a);
    		b>>=1;
    	}
    	return res;
    }
    const int MAXN=2e5+10;
    int rev[MAXN],omega[MAXN],inv[MAXN];
    void rev_init(int n,int lim)
    {
    	for(int i=0;i<n;++i)
    	{
    		int t=0;
    		for(int j=0;j<lim;++j)
    			if((i>>j)&1)
    				t|=1<<(lim-j-1);
    		rev[i]=t;
    	}
    }
    void omega_init(int n)
    {
    	for(int l=2;l<=n;l<<=1)
    	{
    		omega[l]=fpow(G,(P-1)/l);
    		inv[l]=fpow(omega[l],P-2);
    	}
    }
    void NTT(int *a,int n,int lim,int invflag)
    {
    	for(int i=0;i<n;++i)
    	{
    		if(i<rev[i])
    			swap(a[i],a[rev[i]]);
    	}
    	for(int l=2;l<=n;l<<=1)
    	{
    		int m=l>>1;
    		int gi=omega[l];
    		if(invflag)
    			gi=inv[l];
    		for(int *p=a;p!=a+n;p+=l)
    		{
    			int g=1;
    			for(int i=0;i<m;++i)
    			{
    				int t=mul(g,p[i+m]);
    				p[i+m]=add(p[i],P-t);
    				p[i]=add(p[i],t);
    				g=mul(g,gi);
    			}
    		}
    	}
    	if (invflag)
    	{
    		int invn=fpow(n,P-2);
    		for(int i=0;i<n;++i)
    			a[i]=mul(a[i],invn);
    	}
    }
    int f[MAXN],g[MAXN],a[MAXN],b[MAXN];
    void solve(int l,int r,int lim)//[l,r)
    {
    	if(lim<=0)
    		return;
    	int mid=(l+r)>>1,len=r-l;
    	solve(l,mid,lim-1);
    	rev_init(len,lim);
    	for(int i=0;i<len/2;++i)
    		a[i]=f[l+i];
    	for(int i=len/2;i<len;++i)
    		a[i]=0;
    	for(int i=0;i<len;++i)
    		b[i]=g[i];
    	NTT(a,len,lim,false);
    	NTT(b,len,lim,false);
    	for(int i=0;i<len;++i)
    		a[i]=mul(a[i],b[i]);
    	NTT(a,len,lim,true);
    	for(int i=len/2;i<len;++i)
    		f[i+l]=add(f[i+l],a[i]);
    	solve(mid,r,lim-1);
    }
    int main()
    {
    	int n=read();
    	f[0]=1;
    	for(int i=1;i<n;++i)
    		g[i]=read();
    	int N=1,lim=0;
    	while(N<n)
    		N<<=1,++lim;
    	omega_init(N);
    	solve(0,N,lim);	
    	for(int i=0;i<n;++i)
    		printf("%d ",f[i]);
    	puts("");
        return 0;
    }
    

    多项式求逆

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    int read()
    {
    	int out=0,sgn=1;
    	char jp=getchar();
    	while(jp!='-' && (jp<'0' || jp>'9'))
    		jp=getchar();
    	if(jp=='-')
    		sgn=-1,jp=getchar();
    	while(jp>='0' && jp<='9')
    		out=out*10+jp-'0',jp=getchar();
    	return out*sgn;
    }
    const int MAXN=4e5+10;
    const int P=998244353,G=3;
    int add(int a,int b)
    {
    	return (a+b>=P)?(a+b-P):(a+b);
    }
    int mul(int a,int b)
    {
    	return 1LL * a * b % P;
    }
    int fpow(int a,int b)
    {
    	int res=1;
    	while(b)
    	{
    		if(b&1)
    			res=mul(res,a);
    		a=mul(a,a);
    		b>>=1;
    	}
    	return res;
    }
    int rev[MAXN],omega[MAXN],inv[MAXN];
    int curn;
    void init(int n)
    {
    	for(int i=0;i<n;++i)
    		rev[i]=(rev[i>>1]>>1)|((i&1)*(n>>1));
    	for(int l=2; l<=n; l<<=1)
    	{
    		omega[l]=fpow(G,(P-1)/l);
    		inv[l]=fpow(omega[l],P-2);
    	}
    	curn=n;
    }
    void DFT(int *a,int n,bool invflag)
    {
    	if(curn!=n)
    		init(n);
    	for(int i=0; i<n; ++i)
    		if(i<rev[i])
    			swap(a[i],a[rev[i]]);
    	for(int l=2; l<=n; l<<=1)
    	{
    		int m=(l>>1);
    		int gi=omega[l];
    		if(invflag)
    			gi=inv[l];
    		for(int *p=a; p!=a+n; p+=l)
    		{
    			int g=1;
    			for(int i=0; i<m; ++i)
    			{
    				int t=mul(g,p[i+m]);
    				p[i+m]=add(p[i],P-t);
    				p[i]=add(p[i],t);
    				g=mul(g,gi);
    			}
    		}
    	}
    	if(invflag)
    	{
    		int invn=fpow(n,P-2);
    		for(int i=0; i<n; ++i)
    			a[i]=mul(a[i],invn);
    	}
    }
    int a[MAXN],b[MAXN];
    void NTT(int *A,int *B,int *C,int lenA,int lenB)
    {
    	int lenC=lenA+lenB-1,n=1;
    	while(n<lenC)
    		n<<=1;
    	for(int i=0;i<lenA;++i)
    		a[i]=A[i];
    	for(int i=lenA;i<n;++i)
    		a[i]=0;
    	for(int i=0;i<lenB;++i)
    		b[i]=B[i];
    	for(int i=lenB;i<n;++i)
    		b[i]=0;
    	DFT(a,n,false);
    	DFT(b,n,false);
    	for(int i=0; i<n; ++i)
    		C[i]=mul(a[i],b[i]);
    	DFT(C,n,true);
    }
    int tmp[MAXN];
    void poly_inverse(int *A,int *B,int n)
    {
    	B[0]=fpow(A[0],P-2);
    	int k=0;
    	for(int i=2;i<=n;i<<=1)
    	{
    		++k;
    		NTT(A,B,tmp,i,i);
    		NTT(tmp,B,tmp,i,i);
    		for(int j=0;j<i;++j)
    			B[j]=add(mul(2,B[j]),P-tmp[j]);
    	}
    }
    int poly[MAXN],invpoly[MAXN];
    int main()
    {
    	int n=read();
    	for(int i=0;i<n;++i)
    		poly[i]=read();
    	int N=1,lim=0;
    	while((1<<lim)<n)
    		++lim,N<<=1;
    	poly_inverse(poly,invpoly,N);
    	for(int i=0;i<n;++i)
    		printf("%d ",invpoly[i]);
    	puts("");
    	return 0;
    }
    
    

    多项式除法/多项式取模

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    int read()
    {
    	int out=0,sgn=1;
    	char jp=getchar();
    	while(jp!='-' && (jp<'0' || jp>'9'))
    		jp=getchar();
    	if(jp=='-')
    		sgn=-1,jp=getchar();
    	while(jp>='0' && jp<='9')
    		out=out*10+jp-'0',jp=getchar();
    	return out*sgn;
    }
    const int MAXN=4e5+10;
    const int P=998244353,G=3;
    int add(int a,int b)
    {
    	return (a+b>=P)?(a+b-P):(a+b);
    }
    int mul(int a,int b)
    {
    	return 1LL * a * b % P;
    }
    int fpow(int a,int b)
    {
    	int res=1;
    	while(b)
    	{
    		if(b&1)
    			res=mul(res,a);
    		a=mul(a,a);
    		b>>=1;
    	}
    	return res;
    }
    int rev[MAXN],omega[MAXN],inv[MAXN];
    int curn;
    void init(int n)
    {
    	for(int i=0;i<n;++i)
    		rev[i]=(rev[i>>1]>>1)|((i&1)*(n>>1));
    	for(int l=2; l<=n; l<<=1)
    	{
    		omega[l]=fpow(G,(P-1)/l);
    		inv[l]=fpow(omega[l],P-2);
    	}
    	curn=n;
    }
    void DFT(int *a,int n,bool invflag)
    {
    	if(curn!=n)
    		init(n);
    	for(int i=0; i<n; ++i)
    		if(i<rev[i])
    			swap(a[i],a[rev[i]]);
    	for(int l=2; l<=n; l<<=1)
    	{
    		int m=(l>>1);
    		int gi=omega[l];
    		if(invflag)
    			gi=inv[l];
    		for(int *p=a; p!=a+n; p+=l)
    		{
    			int g=1;
    			for(int i=0; i<m; ++i)
    			{
    				int t=mul(g,p[i+m]);
    				p[i+m]=add(p[i],P-t);
    				p[i]=add(p[i],t);
    				g=mul(g,gi);
    			}
    		}
    	}
    	if(invflag)
    	{
    		int invn=fpow(n,P-2);
    		for(int i=0; i<n; ++i)
    			a[i]=mul(a[i],invn);
    	}
    }
    int a[MAXN],b[MAXN];
    void NTT(int *A,int *B,int *C,int lenA,int lenB)
    {
    	int lenC=lenA+lenB-1,n=1;
    	while(n<lenC)
    		n<<=1;
    	for(int i=0;i<lenA;++i)
    		a[i]=A[i];
    	for(int i=lenA;i<n;++i)
    		a[i]=0;
    	for(int i=0;i<lenB;++i)
    		b[i]=B[i];
    	for(int i=lenB;i<n;++i)
    		b[i]=0;
    	DFT(a,n,false);
    	DFT(b,n,false);
    	for(int i=0; i<n; ++i)
    		C[i]=mul(a[i],b[i]);
    	DFT(C,n,true);
    }
    int tmp[MAXN];
    void poly_inverse(int *A,int *B,int n)
    {
    	for(int i=0;i<2*n;++i)
    		B[i]=0;
    	B[0]=fpow(A[0],P-2);
    	int k=0;
    	for(int i=2;i<=n;i<<=1)
    	{
    		++k;
    		NTT(A,B,tmp,i,i);
    		NTT(tmp,B,tmp,i,i);
    		for(int j=0;j<i;++j)
    			B[j]=add(mul(2,B[j]),P-tmp[j]);
    	}
    }
    void poly_rev(int *A,int n)//n->最高项次数 
    {
    	for(int i=0;i<n-i;++i)
    		swap(A[i],A[n-i]);
    }
    int InvB[MAXN];
    int ModA[MAXN],ModB[MAXN];
    void poly_division(int *A,int *B,int *D,int *R,int n,int m)
    {
    	poly_rev(A,n);
    	poly_rev(B,m);
    	for(int i=0;i<n-m+1;++i)
    		ModA[i]=A[i],ModB[i]=B[i];
    	int N=1;
    	while(N<n-m+1)
    		N<<=1;
    	poly_inverse(ModB,InvB,N);
    	for(int i=n-m+1;i<N;++i)
    		InvB[i]=0;
    	NTT(ModA,InvB,D,n-m+1,n-m+1);
    	poly_rev(D,n-m);
    	poly_rev(A,n);
    	poly_rev(B,m);
    	NTT(B,D,R,m,n-m+1);
    	for(int i=0;i<n;++i)
    		R[i]=add(A[i],P-R[i]);
    }
    int A[MAXN],B[MAXN],D[MAXN],R[MAXN];
    int main()
    {
    	int n=read(),m=read();
    	for(int i=0;i<=n;++i)
    		A[i]=read();
    	for(int i=0;i<=m;++i)
    		B[i]=read();
    	poly_division(A,B,D,R,n,m);
    	for(int i=0;i<n-m+1;++i)
    		printf("%d ",D[i]);
    	puts("");
    	for(int i=0;i<m;++i)
    		printf("%d ",R[i]);
    	puts("");
    	return 0;
    }
    
    

    多项式 (ln)

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    int read()
    {
    	int out=0,sgn=1;
    	char jp=getchar();
    	while(jp!='-' && (jp<'0' || jp>'9'))
    		jp=getchar();
    	if(jp=='-')
    		sgn=-1,jp=getchar();
    	while(jp>='0' && jp<='9')
    		out=out*10+jp-'0',jp=getchar();
    	return out*sgn;
    }
    const int MAXN=4e5+10;
    const int P=998244353,G=3;
    int add(int a,int b)
    {
    	return (a+b>=P)?(a+b-P):(a+b);
    }
    int mul(int a,int b)
    {
    	return 1LL * a * b % P;
    }
    int fpow(int a,int b)
    {
    	int res=1;
    	while(b)
    	{
    		if(b&1)
    			res=mul(res,a);
    		a=mul(a,a);
    		b>>=1;
    	}
    	return res;
    }
    int rev[MAXN],omega[MAXN],inv[MAXN];
    int curn;
    void init(int n)
    {
    	for(int i=0;i<n;++i)
    		rev[i]=(rev[i>>1]>>1)|((i&1)*(n>>1));
    	for(int l=2; l<=n; l<<=1)
    	{
    		omega[l]=fpow(G,(P-1)/l);
    		inv[l]=fpow(omega[l],P-2);
    	}
    	curn=n;
    }
    void DFT(int *a,int n,bool invflag)
    {
    	if(curn!=n)
    		init(n);
    	for(int i=0; i<n; ++i)
    		if(i<rev[i])
    			swap(a[i],a[rev[i]]);
    	for(int l=2; l<=n; l<<=1)
    	{
    		int m=(l>>1);
    		int gi=omega[l];
    		if(invflag)
    			gi=inv[l];
    		for(int *p=a; p!=a+n; p+=l)
    		{
    			int g=1;
    			for(int i=0; i<m; ++i)
    			{
    				int t=mul(g,p[i+m]);
    				p[i+m]=add(p[i],P-t);
    				p[i]=add(p[i],t);
    				g=mul(g,gi);
    			}
    		}
    	}
    	if(invflag)
    	{
    		int invn=fpow(n,P-2);
    		for(int i=0; i<n; ++i)
    			a[i]=mul(a[i],invn);
    	}
    }
    int a[MAXN],b[MAXN];
    void NTT(int *A,int *B,int *C,int lenA,int lenB)
    {
    	int lenC=lenA+lenB-1,n=1;
    	while(n<lenC)
    		n<<=1;
    	for(int i=0;i<lenA;++i)
    		a[i]=A[i];
    	for(int i=lenA;i<n;++i)
    		a[i]=0;
    	for(int i=0;i<lenB;++i)
    		b[i]=B[i];
    	for(int i=lenB;i<n;++i)
    		b[i]=0;
    	DFT(a,n,false);
    	DFT(b,n,false);
    	for(int i=0; i<n; ++i)
    		C[i]=mul(a[i],b[i]);
    	DFT(C,n,true);
    }
    int tmp[MAXN];
    void poly_inverse(int *A,int *B,int n)
    {
    	for(int i=0;i<2*n;++i)
    		B[i]=0;
    	B[0]=fpow(A[0],P-2);
    	int k=0;
    	for(int i=2;i<=n;i<<=1)
    	{
    		++k;
    		NTT(A,B,tmp,i,i);
    		NTT(tmp,B,tmp,i,i);
    		for(int j=0;j<i;++j)
    			B[j]=add(mul(2,B[j]),P-tmp[j]);
    	}
    }
    void poly_diff(int *A,int n)
    {
    	for(int i=0;i<n-1;++i)
    		A[i]=mul(A[i+1],i+1);
    }
    void poly_int(int *A,int n)
    {
    	for(int i=n;i>=1;--i)
    		A[i]=mul(A[i-1],fpow(i,P-2));
    }
    int InvA[MAXN];
    void ln(int *A,int *B,int n)
    {
    	poly_inverse(A,InvA,n);
    	poly_diff(A,n);
    	NTT(A,InvA,B,n,n);
    	poly_int(B,n);
    	B[0]=0;
    }
    int A[MAXN],B[MAXN];
    int main()
    {
    	int n=read();
    	int N=1;
    	while(N<n)
    		N<<=1;
    	for(int i=0;i<n;++i)
    		A[i]=read();
    	ln(A,B,N);
    	for(int i=0;i<n;++i)
    		printf("%d ",B[i]);
    	puts("");
    	return 0;
    }
    
    

    多项式 (exp)

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    int read()
    {
    	int out=0,sgn=1;
    	char jp=getchar();
    	while(jp!='-' && (jp<'0' || jp>'9'))
    		jp=getchar();
    	if(jp=='-')
    		sgn=-1,jp=getchar();
    	while(jp>='0' && jp<='9')
    		out=out*10+jp-'0',jp=getchar();
    	return out*sgn;
    }
    const int MAXN=4e5+10;
    const int P=998244353,G=3;
    int add(int a,int b)
    {
    	return (a+b>=P)?(a+b-P):(a+b);
    }
    int mul(int a,int b)
    {
    	return 1LL * a * b % P;
    }
    int fpow(int a,int b)
    {
    	int res=1;
    	while(b)
    	{
    		if(b&1)
    			res=mul(res,a);
    		a=mul(a,a);
    		b>>=1;
    	}
    	return res;
    }
    int rev[MAXN],omega[MAXN],inv[MAXN];
    int curn;
    void init(int n)
    {
    	for(int i=0;i<n;++i)
    		rev[i]=(rev[i>>1]>>1)|((i&1)*(n>>1));
    	for(int l=2; l<=n; l<<=1)
    	{
    		omega[l]=fpow(G,(P-1)/l);
    		inv[l]=fpow(omega[l],P-2);
    	}
    	curn=n;
    }
    void DFT(int *a,int n,bool invflag)
    {
    	if(curn!=n)
    		init(n);
    	for(int i=0; i<n; ++i)
    		if(i<rev[i])
    			swap(a[i],a[rev[i]]);
    	for(int l=2; l<=n; l<<=1)
    	{
    		int m=(l>>1);
    		int gi=omega[l];
    		if(invflag)
    			gi=inv[l];
    		for(int *p=a; p!=a+n; p+=l)
    		{
    			int g=1;
    			for(int i=0; i<m; ++i)
    			{
    				int t=mul(g,p[i+m]);
    				p[i+m]=add(p[i],P-t);
    				p[i]=add(p[i],t);
    				g=mul(g,gi);
    			}
    		}
    	}
    	if(invflag)
    	{
    		int invn=fpow(n,P-2);
    		for(int i=0; i<n; ++i)
    			a[i]=mul(a[i],invn);
    	}
    }
    int a[MAXN],b[MAXN];
    void NTT(int *A,int *B,int *C,int lenA,int lenB)
    {
    	int lenC=lenA+lenB-1,n=1;
    	while(n<lenC)
    		n<<=1;
    	for(int i=0;i<lenA;++i)
    		a[i]=A[i];
    	for(int i=lenA;i<n;++i)
    		a[i]=0;
    	for(int i=0;i<lenB;++i)
    		b[i]=B[i];
    	for(int i=lenB;i<n;++i)
    		b[i]=0;
    	DFT(a,n,false);
    	DFT(b,n,false);
    	for(int i=0; i<n; ++i)
    		C[i]=mul(a[i],b[i]);
    	DFT(C,n,true);
    }
    int tmp[MAXN];
    void poly_inverse(int *A,int *B,int n)
    {
    	for(int i=0;i<2*n;++i)
    		B[i]=0;
    	B[0]=fpow(A[0],P-2);
    	int k=0;
    	for(int i=2;i<=n;i<<=1)
    	{
    		++k;
    		NTT(A,B,tmp,i,i);
    		NTT(tmp,B,tmp,i,i);
    		for(int j=0;j<i;++j)
    			B[j]=add(mul(2,B[j]),P-tmp[j]);
    	}
    }
    void poly_diff(int *A,int n)
    {
    	for(int i=0;i<n-1;++i)
    		A[i]=mul(A[i+1],i+1);
    }
    void poly_int(int *A,int n)
    {
    	for(int i=n;i>=1;--i)
    		A[i]=mul(A[i-1],fpow(i,P-2));
    }
    int InvA[MAXN],tmpA[MAXN];
    void poly_ln(int *A,int *B,int n)
    {
    	for(int i=0;i<n;++i)
    		tmpA[i]=A[i];
    	poly_inverse(tmpA,InvA,n);
    	poly_diff(tmpA,n);
    	NTT(tmpA,InvA,B,n,n);
    	poly_int(B,n);
    	B[0]=0;
    	for(int i=0;i<n;++i)
    		tmpA[i]=0;
    }
    int lnB[MAXN];
    void poly_exp(int *A,int *B,int n)
    {
    	if(n==1)
    	{
    		B[0]=1;
    		return;
    	}
    	poly_exp(A,B,n>>1);
    	for(int i=0;i<n;++i)
    		lnB[i]=0;
    	poly_ln(B,lnB,n);
    	for(int i=0;i<n;++i)
    		lnB[i]=add(A[i],P-lnB[i]);
    	lnB[0]=add(lnB[0],1);
    	NTT(B,lnB,B,n>>1,n);
    	for(int i=n;i<(n+(n>>1));++i)
    		B[i]=0;		
    }
    int A[MAXN],B[MAXN];
    int main()
    {
    	int n=read();
    	for(int i=0;i<n;++i)
    		A[i]=read();
    	int N=1;
    	while(N<n)
    		N<<=1;
    	poly_exp(A,B,N);
    	for(int i=0;i<n;++i)
    		printf("%d ",B[i]);
    	puts("");
    	return 0;
    }
    
    
  • 相关阅读:
    JSP
    结束程序-wpscloudsvr 程序没有响应,要返回Windows并检查程序状态,请单击“取消”,如果选择立即结束程序,你会失去
    解决Serlet API没导进导致的错误
    JDBC工具类
    数据库小项目
    数据库外键主键
    Mysql操作表时报错Table doesn't exist解决办法
    这大概是最细的YOLOX中的Mosaic And Mixup 实现源码分析了吧
    Sigcomm20 Hoyan 阅读笔记
    定时获取最新ssr服务器的方法
  • 原文地址:https://www.cnblogs.com/jklover/p/10666102.html
Copyright © 2020-2023  润新知