
可以知道,对于计算机的储存和处理,我们使用一个double数对来保存复数,同时运算的时候大量的运用了三角函数,浮点乘法等。撇开低效率不谈,光是其精确度都不会太高!
对于数字的估计可以知道最终的结果可能非常大(浮点数),之后各种误差开始积累~而且速度越来越慢。
于是对于n很大的情况,一般来说系数不会太大。
下面介绍一种vb神教我的思想。

这样就把 复数对应到了一个整数,之后一切都在mod P系统内考虑。显然如果最终得到的结果是小数的话,那么是无法等价的。
其中,由于N经常是2的次幂,于是我们可以通过 构造 P = c * (2^k) + 1类的素数来达到目的。
例如在整系数的多项式乘法中,大整数乘法中。。。这些的最终结果均为整数,于是可以用此来等价。
下面来举一个例子:
例子:
我们按照数论替换的思路来YY看吧……
首先我们找到一个素数P以及它的原根G:
P = 1004535809
G = 3
此时G^(P-1)/8 = 395918948 (mod P)
之后按照例子的做法带入,而已得到A,B序列:
A = {21 648936765 369939602853529083 7 128750538 634596211 377855264}
B = {9 107604863 445555772536309069 3 745698602 558980033 619459092}
对比发现,对于原来是整数项的,得到的结果相同(想想为什么?),同时纯复数项的各种不同(为什么,通过这个整数是否有可能还原原复数呢?)
C = {189 956821336 1512323231000195688 21 603796229 853303436 452794142}
接下来我们知道是需要将C的每个元素取共轭,然后再做一次FFT,并将结果/N得到最终答案。
问题来了,复数都被我搞成一坨一坨的整数了,如何“共轭”?

于是牛逼的事情发生了,只需要第0项不变,其余的通过 k -> N – k(1 <= k 的映射交换位置就完成了所谓的“共轭”。
之后就是裸的FFT了,并将得到的结果乘上N的逆元即可。
http://61.187.179.132:8080/JudgeOnline/showproblem?problem_id=2179
此题是高精度乘法的题目,使用以上算法能在2000~3000MS通过
http://61.187.179.132:8080/JudgeOnline/showproblem?problem_id=2194
此题是类多项式乘法的题目,使用以上算法能在6000ms+通过
https://www.spoj.pl/problems/TSUM/
此题为裸FFT + 容斥计数
** 注意要点: 当系数的结果过大,需要选择合适的P
【FFT高精度乘法(数论变换)代码】
#include
#include
#include<string.h>
#include
#include<string>
#include
阅读全文
类别:数论 查看评论