FFT模板+NTT模板

2 篇文章 0 订阅

嫖的模板,原理未知,用于多项式乘法。
将a多项式的系数赋值给a[i].x,b多项式的系数赋值给b[i].x然后solve(n,m)即可。
FFT模板(未初始化)

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
const int MAX_N=10100000;
const double Pi=acos(-1.0);
inline int read(){
    char c=getchar();
    int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}
struct complex{
    double x,y;
    complex(double xx=0,double yy=0){x=xx,y=yy;}
}a[MAX_N],b[MAX_N];
complex operator+(complex a,complex b){return complex(a.x+b.x , a.y + b.y);}
complex operator-(complex a,complex b){return complex(a.x-b.x , a.y - b.y);}
complex operator*(complex a,complex b){return complex(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);}
int l,r[MAX_N];
int limit=1;
void FFT(complex *A,int type){
    for(int i=0;i<limit;i++){
        if(i<r[i]) 
        swap(A[i],A[r[i]]); //求出要迭代的序列
    }
    for(int mid=1;mid<limit;mid<<=1){ //待合并区间的长度的一半
        complex Wn(cos(Pi/mid),type*sin(Pi/mid)); //单位根
        for(int R=mid<<1,j=0;j<limit;j+=R){ //R是区间的长度,j表示前已经到哪个位置了
            complex w(1,0); //幂
            for(int k=0;k<mid;k++,w=w*Wn){ //枚举左半部分
                complex x=A[j+k],y=w*A[j+mid+k]; //蝴蝶效应
                A[j+k]=x+y;
                A[j+mid+k]=x-y;
            }
        }
    }
}
void solve(int n,int m){//a[i].x/limit+0.5的int型就是多项式乘法后x^i的系数 
    limit=1; 
    while(limit<=n+m){
        limit<<=1,l++;
    }
    for(int i=0;i<limit;i++)
    r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
    FFT(a,1);
    FFT(b,1);
    for(int i=0;i<=limit;i++)
    a[i]=a[i]*b[i];
    FFT(a,-1);
}
int main(void){
    int n,m,i,x;
    n=read();m=read();
    for(i=0;i<=n;i++)
    a[i].x=read();
    for(i=0;i<=m;i++)
    b[i].x=read();
    solve(n,m);
    for(i=0;i<=n+m;i++){
        printf("%d",(int)(a[i].x/limit+0.5));
        if(i!=n+m)
        printf(" ");
        else
        printf("\n");
    }
    return 0;
}

NTT模板(适用于MOD为998244353)
已经初始化
每次使用前记住把a数组和b数组都情况,如果a数组和b数组是a[i]+=x的话!!!

#include<iostream>
#include<cstdio>
using namespace std;
const int MAX_N=3*1010000;
const int MOD=998244353;
const int G=3;
const int Gi=332748118;
inline int read(){
    char c=getchar();
    int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}
int limit=1,L,r[MAX_N];
long long a[MAX_N],b[MAX_N];
inline long long pow_mod(long long a,long long n,long long m){
    long long ans=1;
    while(n){
        if(n&1){
            ans=(ans*a)%m;
        }
        a=(a*a)%m;
        n>>=1;
    }
    return ans;
}
inline void NTT(long long *A,int type) {
    for(int i=0;i<limit;i++){
        if(i<r[i])
        swap(A[i],A[r[i]]);
    }
    for(int mid=1;mid<limit;mid<<=1){    
        long long Wn=pow_mod(type==1?G:Gi,(MOD-1)/(mid<<1),MOD);
        for(int j=0;j<limit;j+=(mid<<1)){
            long long w=1;
            for(int k=0;k<mid;k++,w=(w*Wn)%MOD){
                int x=A[j+k],y=w*A[j+k+mid]%MOD;
                A[j+k]=(x+y)%MOD,
                A[j+k+mid]=(x-y+MOD)%MOD;
            }
        }
    }
}
void solve(int n,int m){//a[i]即为多项式乘法后x^i对MOD取模后的系数 
    limit=1;
    L=0;
    while(limit<=n+m){
        limit<<=1,L++;
    }
    for(int i=0;i<limit;i++)
    r[i]=(r[i>>1]>>1)|((i&1)<<(L-1));
 for(int i=n+1;i<limit;i++)
 a[i]=0;
 for(int i=m+1;i<limit;i++)
 b[i]=0;
    NTT(a,1);
    NTT(b,1);    
    for(int i=0;i<limit;i++)
    a[i]=(a[i]*b[i])%MOD;
    NTT(a,-1);    
    long long inv=pow_mod(limit,MOD-2,MOD);
    for(int i=0;i<=n+m;i++)
    a[i]=a[i]*inv%MOD;
}
int main(void){
    int n,m,i;
    n=read();m=read();
    for(i=0;i<=n;i++)
    a[i]=(read()+MOD)%MOD;
    for(i=0;i<=m;i++)
    b[i]=(read()+MOD)%MOD;
    solve(n,m);
    for(i=0;i<=n+m;i++)
    cout<<a[i]<<" ";
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值