FFT中的一个常见小问题(递推式)

FFT中的一个常见小问题

这里不细说FFT的内容,详细内容看这些就足以了解大概了

小学生都能看懂的FFT!!!
FFT详解
补充——FFT中的二进制翻转问题

主要是对学习过程中一个容易困扰的小问题进行解释,以便于理解

  • 用FFT将多项式的系数转换为点值时,原系数数组a最后存的是不同的点值,而不是只有第一个是点值
    这一点最开始困扰了我很久
    A ( x ) = a 0 + a 1 x + a 2 x 2 + . . . + a n 1 x n 1 A(x)=a_0+a_1x+a_2x^2+...+a_{n−1}x^{n−1} A(x)=a0+a1x+a2x2+...+an1xn1
    则可将其移项 A ( x ) = ( a 0 + a 2 x 2 + . . . + a n 2 x n 2 ) + ( a 1 x + a 3 x 3 + . . . + a n 1 x n 1 ) A(x)=(a_0+a_2x^2+...+a_{n−2}x^{n−2})+(a_1x+a_{3}x^3+...+a_{n−1}x^{n−1}) A(x)=(a0+a2x2+...+an2xn2)+(a1x+a3x3+...+an1xn1)
    a的下标为偶数的放在一起 A 1 ( x ) = a 0 + a 2 x + . . . + a n 2 x n 2 1 A_1(x)=a_0+a_2x+...+a_{n−2}xn^{2−1} A1(x)=a0+a2x+...+an2xn21
    a的下标为奇数的放在一起 A 2 ( x ) = a 1 + a 3 x + . . . + a n 1 x n 2 1 A_2(x)=a_1+a_3x+...+a_{n−1}xn^{2−1} A2(x)=a1+a3x+...+an1xn21
    A ( x ) = A 1 ( x 2 ) + x A 2 ( x 2 ) A(x)=A_1(x^2)+xA_2(x^2) A(x)=A1(x2)+xA2(x2)
    注意此处为 x 2 x^2 x2所以有
    A ( x ) = A 1 ( x 2 ) x A 2 ( x 2 ) A(-x)=A_1(x^2)-xA_2(x^2) A(x)=A1(x2)xA2(x2)
    由于单位根的特殊性质,有
    性质一 ω n k + n 2 = ω n k ω_n^{k+\frac{n}{2}}=-ω_n^k ωnk+2n=ωnk
    性质二 ω n k = ω 2 n 2 k ω_n^k=ω_{2n}^{2k} ωnk=ω2n2k
    所以才有了代码中的那两行

    for (int i=0;i<=mid-1;++i){
         buf[i]=a[i]+w*a[i+mid];
         buf[i+mid]=a[i]-w*a[i+mid];
         w=w*wn;
     }
    

    也就是说,我们可以由一个答案进而算出另外一个答案,这里可以理解为递推
    所以当我们的递归递到最下面一层后往上走时每次都是将目前答案个数扩大两倍,而且这些答案是由不同的x算出来的,而且由于性质一,我们在计算过程中所用到的不同的 ω x k ω^{x*k} ωxk是没有问题的
    最后附上板子

    原题链接P3803 【模板】多项式乘法(FFT)

    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    using namespace std;
    const int maxn = 4000006;
    const double pi = acos(-1.0);
    struct IO{
        template<class T>
        IO operator >> (T &res){
            res=0;
            char ch;
            bool flag=false;
            while ((ch=getchar())>'9'||ch<'0')	flag|=ch=='-';
            while (ch>='0'&&ch<='9')	res=(res<<3)+(res<<1)+(ch^'0'),ch=getchar();
            if (flag)	res=~res+1;
            return *this;
        }
    }cin;
    struct complex {
        double x,y;
        complex (double xx=0,double yy=0) {x=xx,y=yy;}
    };
    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,bit,len,val;
    int rev[maxn];
    complex a[maxn],b[maxn],ans[maxn],buf[maxn];
    //递归FFT
    void FFT (complex *a,int len,int on_off)//on_off=1 : FFT on_off=-1 : IFFT
    {
        if (len==1)	return ;
        int mid=len/2;
        for (int i=0;i<=mid-1;++i)	buf[i]=a[i*2],buf[i+mid]=a[i*2+1];
        for (int i=0;i<=len;++i)	a[i]=buf[i];
        FFT(a,mid,on_off),FFT(a+mid,mid,on_off);
        complex wn=complex(cos(2*pi/len),on_off*sin(2*pi/len)),w(1,0);
        for (int i=0;i<=mid-1;++i){
            buf[i]=a[i]+w*a[i+mid];
            buf[i+mid]=a[i]-w*a[i+mid];
            w=w*wn;
        }
        for (int i=0;i<=len;++i)	a[i]=buf[i];
    }
    //非递归FFT
    void FFT2 (complex *a,int len,int on_off)//on_off=1 : FFT on_off=-1 : IFFT
    {
        for (int i=0;i<=len-1;++i)
            if (i<rev[i])	swap(a[i],a[rev[i]]);
        for (int i=1;i<len;i<<=1){
            complex wn=complex (cos(pi/i),on_off*sin(pi/i));
            for (int j=0;j<len;j+=(i<<1)){
    	        complex w(1,0);
        	    for (int k=0;k<i;++k){
            	    complex u=a[j+k],t=w*a[i+j+k];
                	a[j+k]=u+t;
                    a[i+j+k]=u-t;
    	            w=w*wn;
        	    }
        	}
    	}
    }
    int main ()
    {
        cin>>n>>m;
        for (int i=0;i<=n;++i)	cin>>val,a[i].x=val;
        for (int i=0;i<=m;++i)	cin>>val,b[i].x=val;
        len=1;
        while (len<=n+m)	++bit,len<<=1;
        for (int i=0;i<=len-1;++i)	rev[i]=(rev[i>>1]>>1)|((i&1)<<(bit-1));
        FFT2(a,len,1);
        FFT2(b,len,1);
        for (int i=0;i<=len;++i)	ans[i]=a[i]*b[i];
        FFT2(ans,len,-1);
        for (int i=0;i<=n+m;++i)	printf("%d ",int(ans[i].x/len+0.5));
        return 0;
    }
    

如仍有问题或有其它问题可在下方指出,博主看到后会尽力解决,Thanks♪(・ω・)ノ

全部评论

相关推荐

面试官人很好,态度和蔼可亲,没答出来时也会引导你去思考。由于是晚上面的,导致我白天一天都有点紧张,面的时候状态也不是很好,正常可能面试官提问完应该思考几秒再答,而我就像抢答一样一口气把所有会的都说出来,这样就导致逻辑比较混乱,东一句西一句的。首先是自我介绍,先把会的技术大致讲一下,由于我八股背的多所以着重讲了一下,Java,go,jvm,MySQL,Redis,计网,操作系统这些,然后一小部分闲聊,然后先问了一下项目,面试官问我这个项目是否落实之类的,直接坦言说是写的练手的,包括之前也写过IM通讯,外卖之类的。然后面试官就把提问的重点放在了八股上。先问了Java:类加载器(答:3种+自定义类加载器、tomcat、原因+双亲委派+好处)JVM参数(答:xmx,xms,newsize这些,问我是如何设定的,我回答是把内存分一半给堆,再把堆分一半给新生代,这方面确实不太了解)然后问了一下并发相关的:线程池(答:线程池的7个参数(忘了线程工厂和阻塞时间了),3个重要参数,还有线程如何启用,为什么要设计最大线程数之类的,提到Java栈默认分配1MB运行时不可以更改)AQS(答:先讲clh是自旋锁+list,然后是AQS在这个基础上做的两个优化,然后举了一下reentrantlock根据state如何获取资源)CAS(答:使用三个字段,aba问题,然后将通常搭配自旋锁实现,面试官问通常会自旋多少次,这个不太了解,答的100,然后问100次大概多少秒,回答微秒级,然后面试官讲了一下怎么做资源可能没用完,意识到可能还需要进行阻塞操作)然后考虑一下Linux命令(top,ps,如何使用管道符过滤线程和使用Linux启动线程没答出来)然后问Redis:持久化机制(答:三种aof,rdb,混合,aof的三个参数刷盘策略,rdb以快照保存,使用bgsave会使用子线程来保存不会阻塞,而aof虽然会阻塞但是只在写完数据后追加一条命令,不会太影响,然后是他俩的优缺点,还有混合是怎么保存数据的)集群模式(答:三种,主从复制到缺点再到哨兵机制,正常使用三个哨兵互相监督,主节点挂了投票选主哨兵然后选主节点,然后额外讲一下脑裂的问题,主节点进行数据更新然后把命令写入aof来同步从节点,最后cluster集群,如何实现,使用16383个哈希槽(艹答成16384了),先根据哈希码取余,再根据节点数取余决定放在哪个节点上,然后问了一下我会怎么选集群模式,首先是cluster的问题,会让管道操作之类的失效,然后哨兵会导致整个集群结构变得复杂,使用小项目可能会考虑哨兵,大的考虑cluster,然后考了一下cluster如果一个节点挂了怎么办,根据节点数重新取余然后数据转移,面试官说这么转移比较慢,有没有别的办法,我隐约记得使用一个类似环形数组的方式,想不起来了)然后考了一下MySQL的b+树(这方面的知识点太多了,导致我什么都想讲逻辑就比较乱,讲了一下聚簇索引,树的叶子节点对应着一张页16KB,MySQL有一个区的概念,把这些页放在同一个区中,这样叶子节点的双向链表遍历时速度更快,然后b+树的扇出比较大(非常二,说成扇度之类的,面试官以为说的是扇区)这样层数就比较小,一行1kb数据的话3层可以放心2000w数据)其他的暂时想不起来了算法是lru,面试官问要不要提示,我说写个,然后写了10分钟左右,说大概写好了,但是面试官指出了2个小错误,第一个马上就改回来了,第二个一直没看出来(大脑这时候已经停止工作了)反问:问学习建议,说根据实际的项目进行深入,考虑应该怎么做,还问了一下组里面是做Java的吗?面试官说他是做go的,组里什么语言都有,语言影响不大,连忙补充了一句我对go的底层有深入源码的学习)结束。总体感觉答得不太好,没有太体现出深度,细节也不够全面。
下一个更好呗:佬,我投完云智一直没消息,多久约的一面啊
查看14道真题和解析
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务