约数相关知识点详解

约数相关知识点详解

本篇随笔讲解信息学奥林匹克竞赛中数学部分的约数相关知识点。大体包括:整数唯一分解定理的推论\(N\)的正约数集合筛选\(1 - N\)每个数的正约数集合。需要读者有不低于高中一年级的数学素养及一定的逻辑推理能力。本篇随笔将不再对一些基本定理和数学知识、概念进行讲解,有需要的同学请自行补习。

  • 整数唯一分解定理的推论

通过质数相关知识点的学习,我们知道了一个正整数可以被分解成若干质数的乘积,数学表示为:
\[ N=\prod_{i=1}^{i=m}{p_i}^{c_i} \]
将其展开,可以得到:
\[ N=1\times p_1\times p_1^2\times\cdots\times p_1^{c_1}\times \cdots\times p_m^{c_m-1}\times p_m^{c_m} \]
通过约数的定义,我们可知这个展开式中的所有元素都是\(N\)的约数。

那么,根据乘法原理,\(N\)的约数个数\(T\)就可以表示为:
\[ T=(1+c_1)\times(1+c_2)\times\cdots\times(1+c_m) \]
即:
\[ T=\prod_{i=1}^{i=m}(1+c_i) \]
这就是正整数的正约数个数表达式

那么,还是根据正整数的唯一分解定理,\(N\)的所有正约数的和\(S\)就是:
\[ S=(1+p_1+\cdots+p_1^{c_1})\times\cdots\times(1+p_m+p_m^{c_m}) \]
即:
\[ S=\prod_{i=1}^{i=m}{(\sum_{j=0}^{j=c_i}{p_i}^{j})} \]
这就是正整数的所有约数和表达式

  • \(N\)的正约数集合

我们知道了一个正整数的约数和和约数个数,但是我们还是不能知道这个正整数的约数到底是什么。想要知道具体的约数,需要枚举实现。

但是约数有一个性质:它是成对出现的(完全平方数除外)。

假如一个正整数\(a\)\(N\)的约数,且\(a\le\sqrt n\),那么必然会有一个正整数\(b\)\(N\)的约数,且\(b\ge\sqrt n\)

而且根据约数的性质,我们完全可以断定,这个\(b\)就是\(\frac{N}{a}\)

因此,和质数的判定对应地,我们使用试除法。同样只需要枚举\(1 - \sqrt N\)的所有数,每枚举到一个可被\(N\)整除的数,就把这个数和\(N\)除这个数所得的数一起加入到约数集合中。

当然,在细节实现上要判一下它是不是完全平方数。

代码:

void factor(int n)
{
    for(int i=1;i<=sqrt(n);i++)
        if(n%i==0)
        {
            f[++cnt]=i;
            if(i!=n/i)
                f[++cnt]=n/i;
        }
}

并且,通过试除法的原理,我们还可以推导出:

一个数的约数个数的上界为\(2\sqrt N\)

  • 筛选\(1-N\)每个数的正约数集合

如果用上述方法进行求解,时间复杂度为\(O(N\sqrt N)\),会被卡。根据约数的定义,我们可以推出:对于每个数\(d\),这个\(1 -N\)的数列中以之为约数的数一定是它的倍数。即\(d,2d,3d,4d\cdots\lfloor N/d\rfloor\times d\)

所以,我们每枚举到一个数的时候,就直接把它的上述倍数加进表格即可。

代码:

vector<int> f[maxn];
void factors(int n)
{
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n/i;j++)
            f[i*j].push_back(i);
}

上述算法的时间复杂度是\(O(NlogN)\)级别的。

猜你喜欢

转载自www.cnblogs.com/fusiwei/p/11439191.html