• HL 7.19 FFT多项式乘法


    前几天写的FFT,写一下自己的理解;

    最近很不爽 生病了 还被踩 吊着锤;

    FFT就是快速解决多项式乘法的问题,闵神讲的课还是比较好的,至少我差不多都听懂了;

    由于我们知道n次多项式可以由n个点唯一确定,那么我们可以将n次多项式的单位根0-n-1带入,但是这样仍然是O(n^2)的;

    前置芝士:复数,欧拉公式,单位根,基本运算水平;

    我们设多项式A(x)的系数为(a0,a1,a2,,an1)

    那么A(x)=a0+a1x+a2x2+a3x3+a4x4+a5x5++an2xn2+an1xn1

    将其下标按照奇偶性分类

    A(x)=(a0+a2x2+a4x4++an2xn2)+(a1x+a3x3+a5x5++an1xn1)
    A1(x)=a0+a2x+a4x2++an2xn21
    A2(x)=a1+a3x+a5x2++an1xn21

    那么A(x)=A1(x2)+xA2(x2)

    不难发现 这个式子只有常数项不同,那么我们发现其实可以将其分治做下去,一直按照下标奇偶分类,递归的去作就好;
    我们记录一个多项式一般是记录其系数的值,而FFT就是把系数表示变成点置表示在变成系数表示;
    我们可以推导出来一个式子,系数其实最后是需要除n的,这样是代码最后一行那样写的原因;
    Ck=nak
    这就是点值和系数之间的关系,反正我是把所有式子推导了一遍,发现不是特别难,所以建议不懂得时候手算一下;
    设出来一组向量,然后表示他和系数之间的关系即可;
    理清一下思路;
    我们用系数表示多项式,但是求值的时候有点麻烦;
    我们考虑用点值表示这个多项式,但是我们最后仍需要系数表示,
    我们尝试去寻找两者关系,最后发现可以分治,所以递归,所以相当于
    系数到点值到系数;
    偷来的图:

    而且写代码的时候建议手写一下复数的运算,尽管c++自带有,但是也就几行,为了不被卡常;

    当然递归版本的FFT又是会被卡掉;

    其中是有一些小优化的,比如蝴蝶操作,小trick,就是主函数里注释的东西,但是我只写了递归版本(小声)所以就先不整理了;

    #include<iomanip>
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<queue>
    #include<deque>
    #include<cmath>
    #include<ctime>
    #include<cstdlib>
    #include<stack>
    #include<algorithm>
    #include<vector>
    #include<cctype>
    #include<utility>
    #include<set>
    #include<bitset>
    #include<map>
    using namespace std;
    const int N=2100010;
    const double pi=acos(-1.0);
    struct complex{
        double r,v;
        complex(double a=0,double b=0):r(a),v(b){}
        inline complex operator+(const complex& b){return complex(r+b.r,v+b.v);}
        inline complex operator-(const complex& b){return complex(r-b.r,v-b.v);}
        inline complex operator*(const complex& b){return complex(r*b.r-v*b.v,v*b.r+r*b.v);}
    };
    inline void swap(complex& a,complex& b){complex t(a);a=b;b=t;}
    int n,m,L,H;
    complex a[N],b[N],temp[N];
    complex w[N];
    
    void FFT(complex* a,int len,int f){
        if(len==1)return;
        for(int i=0;i<len/2;i++)
            temp[i]=a[i*2],temp[i+len/2]=a[i*2+1];
        for(int i=0;i<len;i++)
            a[i]=temp[i];
        FFT(a,len/2,f),FFT(a+len/2,len/2,f);
        complex wn(cos(2*pi/len),f*sin(2*pi/len)),w(1,0);
        for(int i=0;i<len/2;i++){
            complex x=a[i],y=w*a[i+len/2];
            a[i]=x+y,a[i+len/2]=x-y;
            w=w*wn;
        }
    }
    
    int main(){
    //    freopen("a.in","r",stdin);
    //    freopen("a.out","w",stdout);
        ios::sync_with_stdio(false);
        w[0].r=1;
        cin>>n>>m;
        n++; m++;
        for(int i=0;i<n;i++) cin>>a[i].r;
        for(int i=0;i<m;i++) cin>>b[i].r;
        for(L=1,H=0;L<(n+m-1);H++) L<<=1;
    //    for(int i=0;i<L;i++)
    //        R[i]=(R[i<<1]<<1)|((1&i)<<(H-1));
        FFT(a,L,1); FFT(b,L,1);
        for(int i=0;i<L;i++)
            a[i]=a[i]*b[i];
        FFT(a,L,-1);
        for(int i=0;i<n+m-1;i++) cout<<(int)(a[i].r/L+0.5)<<' ';
        return 0;
    }
    View Code

    以上是我对FFT的浅陋理解,可能会有错误,但是写代码的时候和Chdy大佬也是争执了很多不同的看法,可能以后才会补坑吧;

    洛谷的这个模板题解还是不错的,推荐;

  • 相关阅读:
    python多线程
    python Queue
    PHP curl 模拟登陆
    Smarty 插件开发
    Smarty 使用继承方式实现配置
    Smarty include使用
    MongoDB初探系列之二:认识MongoDB提供的一些经常使用工具
    Ubuntu 12.10 安装JDK7
    第17期中国智能家居主题沙龙将于5月23日在京举行
    重温 Win32 API ----- 截屏指定窗体并打印
  • 原文地址:https://www.cnblogs.com/Tyouchie/p/11212005.html
Copyright © 2020-2023  润新知