多项式$fft$,$ntt$,$fwt$初步

Posted 2018hzoicyf

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了多项式$fft$,$ntt$,$fwt$初步相关的知识,希望对你有一定的参考价值。

最近在学多项式和生成函数。

上课听$lnc$大神讲还是$mengbier$。

作为多项式的前置芝士,$fft,ntt$等是必学的。

在此记录一些关于$fft,ntt,fwt$的知识及例题。。。

 


 

FFT:

  应用在处理$sum _{i+j=k} f[i]*g[j]$的卷积上。

  看网上大佬的博客,基本入了门吧。

  自己的关于原理的一些见解:

    多项式有系数表示和点值表示,两种表示方法可以相互转化。

    FFT可以在$O(n*longn)$内解决多项式乘法。

    具体是,点值表示的方法应用在多项式上是$O(n)$的。

    那么如果能在快速时间内将多项式表示成点值,然后$O(n)$处理,再转化成多项式岂不美哉。

    于是可一取单位根作为代入多项式的$x$,用分治算法处理即可。

  板子:

 

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cmath>
 4 #define MAXN 362144
 5 using namespace std;
 6 const double PI=acos(-1);
 7 struct Cp{
 8     double x,y;
 9     Cp(double xx=0,double yy=0){x=xx;y=yy;return ; }
10     friend Cp operator +(Cp a,Cp b){return Cp(a.x+b.x,a.y+b.y); }
11     friend Cp operator -(Cp a,Cp b){return Cp(a.x-b.x,a.y-b.y); }
12     friend Cp operator *(Cp a,Cp b){return Cp(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x); }
13 }a[MAXN],b[MAXN];
14 int n,m;
15 int lim=1,l=-1;
16 int ys[MAXN];
17 inline void FFT(Cp *x,const int &lim,const int &type){
18     for(int i=0;i<lim;++i)if(i<ys[i])swap(x[i],x[ys[i]]);
19     for(int i=1;i<lim;i<<=1){
20         Cp tmp(cos(PI/i),sin(PI/i)*type);
21         for(int j=0,I=i<<1;j<lim;j+=I){
22             Cp w(1,0);
23             for(int k=0;k<i;++k,w=w*tmp){
24                 Cp t1=x[j+k],t2=w*x[k+i+j];
25                 x[j+k]=t1+t2,x[k+i+j]=t1-t2;
26             }
27         }
28     }
29     return ;
30 }
31 int main(){
32     //freopen("da.in","r",stdin);
33     
34     scanf("%d%d",&n,&m);
35     for(int i=0;i<=n;++i)scanf("%lf",&a[i].x);
36     for(int i=0;i<=m;++i)scanf("%lf",&b[i].x);
37     n+=m;
38     for(;lim<=n;lim<<=1,++l);
39     for(int i=0;i<lim;++i)ys[i]=(ys[i>>1]>>1)|((i&1)<<l);
40     FFT(a,lim,1);FFT(b,lim,1);
41     for(int i=0;i<lim;++i)a[i]=a[i]*b[i];
42     FFT(a,lim,-1);
43     for(int i=0;i<=n;++i)printf("%d ",(int)(a[i].x/lim+0.5));
44     puts("");
45     
46     return 0;
47 }

 

 

 

 


 

NTT:

  原理和$FFT$一样。

 1 #include<cstdio>
 2 #include<iostream>
 3 #define MAXN 2197152
 4 #define LL long long
 5 #define swap(x,y) (x^=y,y^=x,x^=y)
 6 using namespace std;
 7 const LL mod=998244353;
 8 const LL G=3,inv_G=332748118;
 9 int n,m;
10 int lim=1,l=-1;
11 int ys[MAXN];
12 LL a[MAXN],b[MAXN];
13 LL qpow(LL a,LL b){
14     LL res=1LL;a%=mod;
15     for(;b;b>>=1,a=a*a%mod)if(b&1)res=res*a%mod;
16     return res%mod;
17 }
18 inline void NTT(LL *x,const int lim,const int type){
19     for(int i=0;i<lim;++i)if(i<ys[i])swap(x[i],x[ys[i]]);
20     for(int i=1;i<lim;i<<=1){
21         const int delta=i<<1;
22         const LL tmp=qpow(type==1?G:inv_G,(mod-1)/delta);
23         for(int j=0;j<lim;j+=delta){
24             LL w=1LL;
25             for(int k=0;k<i;++k,w=w*tmp%mod){
26                 LL t1=x[j+k],t2=w*x[i+j+k]%mod;
27                 x[j+k]=(t1+t2)%mod,x[i+j+k]=(t1-t2+mod)%mod;
28             }
29         }
30     }
31     return ;
32 }
33 int main(){
34     //freopen("da.in","r",stdin);
35     
36     scanf("%d%d",&n,&m);
37     for(int i=0;i<=n;++i)scanf("%lld",&a[i]);
38     for(int i=0;i<=m;++i)scanf("%lld",&b[i]);
39     n+=m;for(;lim<n+2;lim<<=1,++l);
40     for(int i=0;i<lim;++i)ys[i]=(ys[i>>1]>>1)|((i&1)<<l);
41     NTT(a,lim,1);NTT(b,lim,1);
42     for(int i=0;i<lim;++i)a[i]=a[i]*b[i]%mod;
43     NTT(a,lim,-1);
44     LL _inv=qpow(lim,mod-2);
45     for(int i=0;i<=n;++i)printf("%lld ",a[i]*_inv%mod);
46     puts("");
47     
48     return 0;
49 }

 

 

 

 

 

  

  

 

以上是关于多项式$fft$,$ntt$,$fwt$初步的主要内容,如果未能解决你的问题,请参考以下文章

fft,ntt,fwt

FFT/NTT/FMT/FWT题目

与组合数学和多项式斗争到底!

快速傅里叶变换

FFT/NTT及多项式运算模板

「总结」多项式生成函数相关