多项式模板

检查数据:
input:
6
1 2 3 4 5 6
1.NTT多项式求逆

#include<bits/stdc++.h>
#define maxn 2100005
#define LL long long
#define mod 998244353
using namespace std;

int lg[maxn],r[maxn],w[maxn]={1},wlen;
int Pow(int base,int k)
{	int ret=1;
	for(;k;k>>=1,base=1ll*base*base%mod) if(k&1) ret=1ll*ret*base%mod;
	return ret;}
inline void NTT(int A[maxn],int n,int tp)//n=2^k
{
	int lgn = lg[n];
	for(int i=1;i<n;i++) r[i] = (r[i>>1]>>1)|((i&1)<<(lgn-1));
	for(int i=1;i<n;i++) if(i<r[i]) swap(A[i],A[r[i]]);
	for(int L=2;L<=n;L<<=1)
		for(int st=0,l=L>>1,inc=wlen/l;st<n;st+=L)
			for(int k=st,x=0;k<st+l;k++,x+=inc)
			{	int tmp = 1ll *(tp==1?w[x]:w[2*wlen-x])*A[k+l] % mod;
				A[k+l]=(A[k]-tmp)%mod,A[k]=(A[k]+tmp)%mod;}
	if(tp==-1) for(int i=0,inv=Pow(n,mod-2);i<n;i++) A[i]=1ll*A[i]*inv%mod;
}
void Inv(int A[maxn],int B[maxn],int n)
{	B[0] = Pow(A[0],mod-2);
	static int tmp[maxn];
	for(int i=2;i<(n<<1);i<<=1)// mod x^i
	{	for(int j=0;j<i;j++) tmp[j] = j<n?A[j]:0;
		NTT(tmp,i<<1,1),NTT(B,i<<1,1);
		for(int j=0;j<(i<<1);j++) B[j]=1ll*B[j]*(2-1ll*B[j]*tmp[j]%mod)%mod;
		NTT(B,i<<1,-1);	for(int j=min(n,i);j<(i<<1);j++) B[j] = 0;}
}

int a[maxn],b[maxn];
int main()
{
	int n;
	scanf("%d",&n);
	for(wlen=1;(n<<1)>(wlen<<1);wlen<<=1);
	for(int i=1,pw=Pow(3,(mod-1)/(2*wlen));i<=2*wlen;i++) w[i] = 1ll * w[i-1] * pw % mod;
	for(int i=2;i<=2*wlen;i++) lg[i] = lg[i>>1]+1;
	for(int i=0;i<n;i++) scanf("%d",&a[i]);
	Inv(a,b,n);
	for(int i=0;i<n;i++) printf("%d%c",(b[i]+mod)%mod,i==n-1?'\n':' ');
}

output:

2.多项式除法:
感觉我好短啊。

#include<bits/stdc++.h>
#define maxn 2100005
#define LL long long
#define mod 998244353
using namespace std;

int lg[maxn],r[maxn],w[maxn]={1},wlen;
int Pow(int base,int k)
{	int ret=1;
	for(;k;k>>=1,base=1ll*base*base%mod) if(k&1) ret=1ll*ret*base%mod;
	return ret;}
inline void NTT(int A[maxn],int n,int tp)//n=2^k
{	int lgn = lg[n];
	for(int i=1;i<n;i++) r[i] = (r[i>>1]>>1)|((i&1)<<(lgn-1));
	for(int i=1;i<n;i++) if(i<r[i]) swap(A[i],A[r[i]]);
	for(int L=2;L<=n;L<<=1)
		for(int st=0,l=L>>1,inc=wlen/l;st<n;st+=L)
			for(int k=st,x=0;k<st+l;k++,x+=inc)
			{	int tmp = 1ll *(tp==1?w[x]:w[2*wlen-x])*A[k+l] % mod;
				A[k+l]=(A[k]-tmp)%mod,A[k]=(A[k]+tmp)%mod;}
	if(tp==-1) for(int i=0,inv=Pow(n,mod-2);i<n;i++) A[i]=1ll*A[i]*inv%mod;}
void mul(int A[maxn],int B[maxn],int C[maxn],int n,int m)
{	int lgn = lg[n+m]+1,len = 1<<lgn;
	static int sta[maxn];
	for(int i=0;i<len;i++) sta[i]=i<=n?A[i]:0,C[i]=i<=m?B[i]:0;
	NTT(sta,len,1),NTT(C,len,1);
	for(int i=0;i<len;i++) C[i] = 1ll * C[i] * sta[i] % mod;
	NTT(C,len,-1);}
void Inv(int A[maxn],int B[maxn],int n)
{	B[0] = Pow(A[0],mod-2);
	static int tmp[maxn];
	for(int i=2;i<(n<<1);i<<=1)// mod x^i
	{	for(int j=0;j<i;j++) tmp[j] = j<n?A[j]:0;
		NTT(tmp,i<<1,1),NTT(B,i<<1,1);
		for(int j=0;j<(i<<1);j++) B[j]=1ll*B[j]*(2-1ll*B[j]*tmp[j]%mod)%mod;
		NTT(B,i<<1,-1);	for(int j=min(n,i);j<(i<<1);j++) B[j] = 0;}}
void Div(int A[maxn],int B[maxn],int C[maxn],int R[maxn],int n,int m)
{	static int ra[maxn],rb[maxn];
	for(int i=0,lim=max(n,m);i<=lim;i++) ra[i]=i<=n?A[n-i]:0,rb[i]=i<=m?B[m-i]:0;
	Inv(rb,C,n-m+1),mul(ra,C,C,n,n-m);
	for(int i=0;i<=2*n-m;i++) if(i<n-m-i)swap(C[i],C[n-m-i]);else if(i>n-m)C[i]=0;
	mul(C,B,R,n-m,m);for(int i=0;i<=n;i++) R[i]=i<m?(A[i]-R[i])%mod:0;}
void Init(int n)
{	for(wlen=1;n>=(wlen<<1);wlen<<=1);
	for(int i=1,pw=Pow(3,(mod-1)/(2*wlen));i<=2*wlen;i++) w[i]=1ll*w[i-1]*pw%mod;
	for(int i=2;i<=2*wlen;i++) lg[i] = lg[i>>1] + 1;}
int a[maxn],b[maxn],c[maxn],R[maxn];
int main()
{
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i=0;i<=n;i++) scanf("%d",&a[i]);
	for(int i=0;i<=m;i++) scanf("%d",&b[i]);
	Init(n<<1);
	Div(a,b,c,R,n,m);
	for(int i=0;i<=n-m;i++) printf("%d%c",(c[i]+mod)%mod,i==n-m?'\n':' ');
	for(int i=0;i<m;i++) printf("%d%c",(R[i]+mod)%mod,i==m-1?'\n':' ');
}

3.多项式exp
AC Code:(PS : 一旦到了需要多次调用函数的时候很多细节(清零)问题就出来了,以上的代码好像都没有考虑的说。。。。。。求逆,求 L n Ln Ln,求 e x p exp exp都以本代码为准)
63行还是有点短的说。

#include<bits/stdc++.h>
#define maxn 300005
#define mod 998244353
using namespace std;

int lg[maxn],r[maxn],w[maxn]={1},wlen,inv[maxn]={1,1};
int Pow(int base,int k)
{	int ret = 1;
	for(;k;k>>=1,base=1ll*base*base%mod) if(k&1) ret=1ll*ret*base%mod;
	return ret; }
void Init(int n)
{	for(wlen=1;n>=(wlen*2);wlen<<=1);
	for(int i=1,pw=Pow(3,(mod-1)/(2*wlen));i<=2*wlen;i++) w[i] = 1ll * w[i-1] * pw % mod;
	for(int i=2;i<=2*wlen;i++) lg[i] = lg[i>>1] + 1; 
	for(int i=2;i<=2*wlen;i++) inv[i] = 1ll * (mod - mod / i) * inv[mod % i] % mod; }
inline void NTT(int *A,int n,int tp)
{	int lgn = lg[n];
	for(int i=1;i<n;i++) r[i] = (r[i>>1]>>1)|((i&1)<<(lgn-1));
	for(int i=1;i<n;i++) if(i<r[i]) swap(A[i],A[r[i]]);
	for(int L=2;L<=n;L<<=1)
		for(int st=0,l=L>>1,inc=wlen/l;st<n;st+=L)
			for(int k=st,x=0;k<st+l;k++,x+=inc)
			{ 	int tmp = 1ll * (tp==1?w[x]:w[2*wlen-x]) * A[k+l] % mod;
				A[k+l]=(A[k]-tmp)%mod,A[k]=(A[k]+tmp)%mod;}
	if(tp==-1) for(int i=0,inv=Pow(n,mod-2);i<n;i++) A[i]=1ll*A[i]*inv%mod;}
void Inv(int *A,int *B,int n)
{	B[0] = Pow(A[0] , mod-2);
	static int tmp[maxn];
	for(int k=2;k<(n<<1);k<<=1)
	{	for(int i=0,lim=min(k,n);i<(k<<1);i++) tmp[i]=i<lim?A[i]:0,B[i]=i<lim?B[i]:0;
		NTT(tmp,k<<1,1),NTT(B,k<<1,1);
		for(int i=0,lim=k<<1;i<lim;i++) B[i]=1ll*B[i]*(2-1ll*B[i]*tmp[i]%mod)%mod;
		NTT(B,k<<1,-1);for(int i=min(k,n);i<(k<<1);i++) B[i] = 0;}
}
void cLn(int *A,int *B,int n)
{	Inv(A,B,n);
	static int tmp[maxn];
	int lgn = lg[n-1]+2 , len = 1<<lgn;
	for(int i=0;i<len;i++) tmp[i]=i<n-1?1ll*A[i+1]*(i+1)%mod:0;
	NTT(tmp,len,1),NTT(B,len,1);
	for(int i=0;i<len;i++) tmp[i]=1ll*B[i]*tmp[i]%mod;
	NTT(tmp,len,-1);B[0]=0;
	for(int i=1;i<n;i++) B[i] = 1ll * tmp[i-1] * inv[i] % mod; 
	for(int i=n;i<len;i++) B[i] = 0;}
void eXp(int *A,int *B,int n)
{	B[0] = 1;
	static int tmp[maxn];
	for(int k=2;k<(n<<1);k<<=1)
	{	cLn(B,tmp,k);
		for(int i=0,lim=min(n,k);i<(k<<1);i++) tmp[i]=i<lim?((i==0)-tmp[i]+A[i])%mod:0,B[i]=i<lim?B[i]:0;
		NTT(B,k<<1,1),NTT(tmp,k<<1,1);
		for(int i=0;i<(k<<1);i++) B[i]=1ll*B[i]*tmp[i]%mod;
		NTT(B,k<<1,-1);for(int i=min(n,k);i<(k<<1);i++) B[i]=0;}}
int a[maxn],b[maxn];
int main()
{
	int n;
	scanf("%d",&n);
	for(int i=0;i<n;i++) scanf("%d",&a[i]);
	Init(n<<1);
	eXp(a,b,n);
	for(int i=0;i<n;i++) printf("%d%c",(b[i]+mod)%mod,i==n-1?'\n':' ');
}

4多项式开根

#include<bits/stdc++.h>
#define maxn 300005
#define mod 998244353
using namespace std;

int w[maxn]={1},lg[maxn],r[maxn],wlen;
int Pow(int base,int k)
{	int ret = 1;
	for(;k;k>>=1,base=1ll*base*base%mod) if(k&1) ret=1ll*ret*base%mod;
	return ret;}
void Init(int n)
{	for(wlen=1;n>=2*wlen;wlen<<=1);
	for(int i=1,pw=Pow(3,(mod-1)/(2*wlen));i<=2*wlen;i++) w[i]=1ll*w[i-1]*pw%mod;
	for(int i=2;i<=2*wlen;i++) lg[i]=lg[i>>1]+1;}
inline void NTT(int *A,int n,int tp)
{	int lgn = lg[n];
	for(int i=1;i<n;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(lgn-1));
	for(int i=1;i<n;i++) if(i<r[i]) swap(A[i],A[r[i]]);
	for(int L=2;L<=n;L<<=1)
		for(int st=0,l=L>>1,inc=wlen/l;st<n;st+=L)
			for(int k=st,x=0,tmp;k<st+l;k++,x+=inc)
				tmp=1ll*(tp==1?w[x]:w[2*wlen-x])*A[k+l]%mod,
				A[k+l]=(A[k]-tmp)%mod,A[k]=(A[k]+tmp)%mod;
	if(tp==-1) for(int i=0,inv=Pow(n,mod-2);i<n;i++) A[i]=1ll*A[i]*inv%mod;}
void Inv(int *A,int *B,int n)
{	B[0]=Pow(A[0],mod-2),B[1]=B[2]=B[3]=0;
	static int tmp[maxn];
	for(int k=2;k<(n<<1);k<<=1)
	{	for(int i=0;i<(k<<1);i++) tmp[i]=i<k?A[i]:0,B[i]=i<k?B[i]:0;
		NTT(tmp,k<<1,1),NTT(B,k<<1,1);
		for(int i=0;i<(k<<1);i++) B[i]=1ll*B[i]*(2-1ll*B[i]*tmp[i]%mod)%mod;
		NTT(B,k<<1,-1);for(int i=min(k,n);i<(k<<1);i++) B[i]=0;}
}
void Sqt(int *A,int *B,int n)
{	B[0]=1,B[1]=B[2]=B[3]=0;
	static int tmp[2][maxn];
	for(int k=2;k<(n<<1);k<<=1)
	{	for(int i=0;i<(k<<1);i++) tmp[0][i]=i<k?A[i]:0,B[i]=i<k?B[i]:0;
		Inv(B,tmp[1],k),NTT(tmp[0],k<<1,1),NTT(tmp[1],k<<1,1),NTT(B,k<<1,1);
		for(int i=0;i<(k<<1);i++) B[i] = 1ll * (mod+1)/2 * tmp[1][i] % mod * (tmp[0][i]+1ll*B[i]*B[i]%mod) % mod; 
		NTT(B,k<<1,-1);for(int i=k;i<(k<<1);i++) B[i]=0;}}
int n,m;
int a[maxn],b[maxn],c[maxn],d[maxn];
int main()
{
	scanf("%d%d",&n,&m);m++;
	for(int i=0,x;i<n;i++) scanf("%d",&x),a[x]++;
	Init(m<<1);
	for(int i=0;i<=m;i++) b[i] = (i==0) - 4ll * a[i];
	Sqt(b,c,m);	
	c[0]++;
	Inv(c,d,m);
	for(int i=1;i<m;i++) 
		printf("%d\n",(2ll*d[i]%mod+mod)%mod);
}

5.多项式求幂
有3种算法:(后两种只能玩整数幂)
1.多项式exp O ( n log ⁡ n ) ∗ 30 O(n \log n) * 30 O(nlogn)30
2.多项式快速幂,每层3次FFT T ( n ) = T ( n / 2 ) + O ( l e n log ⁡ l e n ) , 实 际 是 O ( l e n log ⁡ l e n log ⁡ n ) T(n) = T(n/2) + O(len \log len),实际是O(len \log len \log n) T(n)=T(n/2)+O(lenloglen)O(lenloglenlogn)
3.多项式快速幂,NTT后对每个数单独进行快速幂然后再NTT回来。 O ( n log ⁡ n ) O(n \log n) O(nlogn)
关于这3者的区别可以看这篇博客
Codeforces 1096G Lucky Tickets

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值