快速判断互质——浅析

这两天碰到一个问题,给定一个范围[1..n], 以及任意数m(1<m<=n), 统计给定域内与m互质的自然数的个数.

我们知道判断两个数互质充分必要条件是,两个数最大公约数=1, 这样,我们只需枚举i(1<=i<=n), 求gcd(i,m)即可,

辗转相除求gcd(i, m) 时间复杂度为logm+logi, 加上枚举时间,复杂度就为为 n*logm+logn!

若问题仅求一次m,近乎线性时间,是不错解决方案;但如果,如此取值m,比如在[1...n]中随即选取k个数,求每个

数在[1..n]中互质的个数,那么问题复杂度就变成O(k*n)了, 若n=50000, k=10000(即5个数中选取1个), 时间近乎数

十秒,这将不可忍受。

另法,快速求得[1..n]中与m不互素的个数res, 则n-res...

费费定理: 若整数i与m不互素,则m所有质因子中,至少一个也是i的质因子

步骤一:分解m求其质因子
 
方法,枚举[2..sqrt(m')]试除m';这里m'初始值m,每次枚举到一个质因子,便除去m'中所有此因子,

因此平均时间远小于sqrt(m), 但最坏情况下仍使sqrt(m), 可以做个优化,预处理[1..n]生成素数表(n=50000, 素数约5000),

筛选法求素数表时间O(3*n),然后直接拿生成的素数试除。

步骤二:求不互质个数

假设m分解后,质因子为p[pCnt], 那么[1...n]中包含这些质因子的数目为:

公式: 若pCnt=3,则

n/p[1]+n/p[2]+n/p[3]-n/(p[1]*p[2])-n/(p[1]*p[3])-n/(p[2]*p[3])+n/(p[1]*p[2]*p[3])

忘了这个叫什么来着,似乎是鸽巢定理的扩展吧。

其实pCnt值非常小,若n=50000, 则pCnt<7, 因为 2*3*5*7*11*13*17 >> 50000

这样,我们就可以简单深搜一下,计算上面公式的值,dfs时间 pCnt*2^pCnt (=384, n=50000时)

如此,总时间为O(k*t) t=sqrt(m)+pCnt*2^pCnt (t<600,n=50000时) 近乎于n无关,

因此,即使n=50000, k=10000, 计算复杂度也不超10^7,1s内, 实际上本机运行,不过几十ms.

至此,问题得到解决,从数十s到几十ms。


应该有更好的算法,期待有志之士... 现在想来,文章内容与题目有些不符,hehe
 

你可能感兴趣的:(算法,优化,扩展)