对于两个n阶多项式的乘法,如果模拟做的话复杂度为O(n^2),利用快速傅里叶变换可以把复杂度降到O(nlogn)。
多项式有两种表示:系数形式和点值表示。如果把两个多项式写成点值形式,那么相乘的复杂度就是O(n)的。FFT的基本思想就是通过把系数形式化成点值形式,相乘之后再化回来,使得复杂度降到O(nlogn)。具体就是先通过巧妙地选取n个复数单位根,利用复数的一些非常好的性质求得DFT,把这一步的复杂度降到O(nlogn),然后将得到的点值相乘后,利用插值再变换成系数形式。插值的过程居然和求DFT的过程惊人的相似,复杂度依然为O(nlogn)。
在实现的时候基本参照算法导论,感觉递归不太好写,就写了个迭代的。N久不用复数了,连基本运算都忘了,导致实现的时候出了一堆错,后来好不容易写好了,结果却一点都不靠谱。查了好久才发现,初始w是1的时候,我把实部和虚部都设成1了,囧。实际上虚部应该是0。改完后发现多项式的表示又出了问题,后来发现我把系数的顺序写反了。然后利用这个做了HDU 1402,就是高精度乘法。WA了几次,很抓狂。后来写了一个程序跑了一组极限数据,居然挂了。仔细观察后发现是精度的问题。因为FFT中间运算过程都是浮点数,但是最后要输出整数,取整的时候舍入精度出了问题,加了1e-3之后过了。
还有一道比较巧妙的FFT的题目,SRM 436 DIV 1 1000pt,做的时候开始Z0忘记取模了,结果还以为是模板的问题,找了很长时间才发现。做题还是要细心啊。
posted on 2009-05-18 16:01
sdfond 阅读(534)
评论(0) 编辑 收藏 引用 所属分类:
Algorithm - Ad Hoc