原创代码,请勿转载!
梅森素数判定:
卢卡斯-莱默检验法:参考https://zh.wikipedia.org/wiki/%E5%8D%A2%E5%8D%A1%E6%96%AF-%E8%8E%B1%E9%BB%98%E6%A3%80%E9%AA%8C%E6%B3%95
卢卡斯-莱默检验法 是迭代算法,需要用到高精度乘法运算。
而现有的乘法运算算法最快的要数 快速傅里叶变换 算法,
可以将两位n-bit的大整数乘法在O(n lg n)计算出来。
FFT简介:快速傅里叶变换, 参考 http://beige.ucs.indiana.edu/B673/node12.html
n = 8 为例子, 计算两个4位数的乘法。
寻找根w使得 w^n = 1.
A[0..7][0..7]: A[i][j] = w^{i*j}, 其中 w^n = 1.
A^{-1} = w^{-1} ^ {i*j}.
对于大整数X和Y,首先做矩阵乘法运算
X' = A*X
Y' = A*Y
然后对X' Y' 对应bit位 对应相乘
Z = X' .* Y' (对应相乘)
最后还原
Z' = A^{-1}*Z
快速傅里叶变换的高效之处在于,A矩阵是具有很强的结构性,因此矩阵乘法运算过程可以优化到O(n lg n).
关于如何选择根w.
采用数论中的 root https://en.wikipedia.org/wiki/Root_of_unity_modulo_n
避免浮点数运算。
对于n=2^k, 寻找大素数MOD,使得 存在 w, w^{2^k}=1 (mod MOD).
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<ctime>
#include<cmath>
#define EXC(a,b) a ^ b ? a ^= b ^= a ^= b : 0
#define EXCB(a,b) a > b ? a ^= b ^= a ^= b : 0
#define FOR(i,a,b) for(int i=(a);i<(b);i++)
#define FORE(i,a,b) for(int i=(a);i<=(b);i++)
#define FORI(TYPE,it,s) fo