FFT/NTT/FWT模板

 

非递归版FFT

源自快速傅里叶变换(FFT)详解

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=5e6+5;
inline int read()
{
    int x=0;
    char ch=getchar();
    while(ch>'9'||ch<'0') ch=getchar();
    while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar();
    return x;
}
const double pi=acos(-1.0);
struct Complex
{
    double x,y;
    Complex (double xx=0,double yy=0)
    {
        x=xx,y=yy;
    }
} a[maxn],b[maxn];
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 N,M;
int l,r[maxn];
int limit=1;
void fast_fast_tle(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;
            }
        }
    }
}
int main()
{
    int N=read(),M=read();
    for(int i=0; i<=N; i++) a[i].x=read();
    for(int i=0; i<=M; i++) b[i].x=read();
    while(limit<=N+M) limit<<=1,l++;
    for(int i=0; i<limit; i++) r[i]=(r[i>>1]>>1)|((i&1)<<(l-1)) ;
    // 在原序列中 i 与 i/2 的关系是 : i可以看做是i/2的二进制上的每一位左移一位得来
    // 那么在反转后的数组中就需要右移一位,同时特殊处理一下奇数
    fast_fast_tle(a,1);
    fast_fast_tle(b,1);
    for(int i=0; i<=limit; i++) a[i]=a[i]*b[i];
    fast_fast_tle(a,-1);
    for(int i=0; i<=N+M; i++) printf("%d ",(int)(a[i].x/limit+0.5));
}

NTT模板

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define RG register
#define MAX 3000000
inline int read()
{
    RG int x=0,t=1;RG char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=-1,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return x*t;
}
const int pr=3;
const int MOD=998244353;
const int phi=MOD-1;
int n,m,r[MAX],l;
int a[MAX],b[MAX];
int fpow(int a,int b)
{
    int s=1;
    while(b){if(b&1)s=1ll*s*a%MOD;a=1ll*a*a%MOD;b>>=1;}
    return s;
}
void NTT(int *P,int opt)
{
    for(int i=0;i<n;++i)if(i<r[i])swap(P[i],P[r[i]]);
    for(int i=1;i<n;i<<=1)
    {
        int W=fpow(pr,phi/(i<<1));
        for(int p=i<<1,j=0;j<n;j+=p)
        {
            int w=1;
            for(int k=0;k<i;++k,w=1ll*w*W%MOD)
            {
                int X=P[j+k],Y=1ll*w*P[i+j+k]%MOD;
                P[j+k]=(X+Y)%MOD;P[i+j+k]=(X-Y+MOD)%MOD;
            }
        }
    }
    if(opt==-1)reverse(&P[1],&P[n]);
}
int main()
{
    n=read();m=read();
    for(int i=0;i<=n;++i)a[i]=read();
    for(int i=0;i<=m;++i)b[i]=read();
    m+=n;
    for(n=1;n<=m;n<<=1)++l;
    for(int i=0;i<n;++i)r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
    NTT(a,1);NTT(b,1);
    for(int i=0;i<n;++i)a[i]=1ll*a[i]*b[i]%MOD;
    NTT(a,-1);
    int inv=fpow(n,MOD-2);
    for(int i=0;i<n;++i)a[i]=1ll*a[i]*inv%MOD;
    for(int i=0;i<=m;++i)printf("%d ",a[i]);puts("");
    return 0;
}

FWT模板

源自yyq的版本稍作修改

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MOD=1e9+7;
const int inv2=5e8+4;
int powmod(int a,int b)
{
    int ans=1;
    while(b)
    {
        if(b&1) ans=(1ll*ans*a)%MOD;
        a=(1ll*a*a)%MOD;
        b>>=1;
    }
    return ans;
}
void FWT_or(int *a,int n,int opt)
{
    while((n&-n)!=n) n+=(n&-n);
    for(int i=1; i<n; i<<=1)
        for(int p=i<<1,j=0; j<n; j+=p)
            for(int k=0; k<i; ++k)
                if(opt==1)a[i+j+k]=(a[j+k]+a[i+j+k])%MOD;
                else a[i+j+k]=(a[i+j+k]+MOD-a[j+k])%MOD;
}
void FWT_and(int *a,int n,int opt)
{
    while((n&-n)!=n) n+=(n&-n);
    for(int i=1; i<n; i<<=1)
        for(int p=i<<1,j=0; j<n; j+=p)
            for(int k=0; k<i; ++k)
                if(opt==1)a[j+k]=(a[j+k]+a[i+j+k])%MOD;
                else a[j+k]=(a[j+k]+MOD-a[i+j+k])%MOD;
}
void FWT_xor(int *a,int n,int opt)
{
    while((n&-n)!=n) n+=(n&-n);
    for(int i=1; i<n; i<<=1)
        for(int p=i<<1,j=0; j<n; j+=p)
            for(int k=0; k<i; ++k)
            {
                ll X=a[j+k],Y=a[i+j+k];
                a[j+k]=(X+Y)%MOD;
                a[i+j+k]=(X+MOD-Y)%MOD;
                if(opt==-1) a[j+k]=1ll*a[j+k]*inv2%MOD,a[i+j+k]=1ll*a[i+j+k]*inv2%MOD;
            }
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值