因子和倍数问题

Published: by Creative Commons Licence

  • Tags:

因子和倍数问题

简单记ϕ(x)表示x的因子数。

题目1:给定正整数g,找到g的所有素因子。其中1g1018

首先考虑如何找到给定数g的所有素因子。这个用Pollard Rho算法就可以了,时间复杂度为O(g1/4(log2g)2),但是实际上跑的飞快。

题目2:给定正整数g,要求找到g的所有因子。其中1g1018

先找到所有素因子,之后可以直接暴力递归搜它的所有因子。后者时间复杂度为O(ϕ(x))。注意这里ϕ(x)只有10万级别大小。

题目3:给定正整数g,以及数p,其中gcd(g,p)=1。要求找到最小的正整数x满足gx=1(modp)。其中1g,p109

由欧拉定理知gφ(p)=1(modp),利用辗转法不难得知xφ(p)。因此我们只需要从φ(p)开始递减即可,不断删除一些素因子,直到不能删为止。在计算出φ(p)后,接下来的时间复杂度为O((log2p)2)

题目4:给定正整数g,考虑g的所有因子。接下来处理n个元素x1,,xn,其中xig的因子。之后对所有g的因子d,计算x中有多少数是是d的因子。

可以发现整除关系可以构成一个非常庞大的有向图,很难搞。但是整除关系实际上原本有向图简单规则得多。

考虑唯一的素数分解g=pc11pckk。我们可以用向量(c1,,ck)来唯一表示g。这时候所有g的因子也可以如法表示。现在问题变成了一个高维数组前缀和。后者计算的时间复杂度为O(kϕ(g))

题目5:给定正整数g。之后给定n个数x1,,xn,要求计算ni=1{kxi(modg)k0}的大小。其中1g1091n105

实际上xi的意义是将所有gcd(xi,g)的倍数全部标记。而问题要求我们计算有多少数最终被标记。接下来我们可以认为xi=gcd(xi,g)

首先对数据进行去重。如果我们直接维护bitset暴力计算的话,时间复杂度为O(dgd),它的值约为O(glnlng)。不是很大。

还有一种更加高效的方式是发现ϕ(g)1200。我们可以根据容斥计算。记录dp(i,j)表示仅考虑x1,,xi,被选中的元素的最小公倍数为j,总共的方案数(带符号,选择奇数次为正号,偶数次为负号)。其对外的贡献只有两种,因此可以O(ϕ(g)2log2g)计算。

最终的结果为dgdp(n,d)×gdn

素数

素数是指大于1,且除了1和自身外,没有其它因子的整数。

π(x)表示所有小于等于x的正整数中素数的数目,在x足够大的时候,π(x)xlnx

素数筛

素数筛用于查找所有小于等于n的所有素数。下面给出一些筛法以及对应的时间复杂度:

  • 暴力判断每个数是否是素数,时间复杂度为O(nn)
  • 欧拉筛,时间复杂度为O(n)
  • 暴力枚举所有数的倍数,并标记它们为合数,时间复杂度为O(nlnn)
  • 埃拉托斯特尼筛法,暴力枚举所有素数的倍数,并标记它们为合数。时间复杂度为O(nlnlnn)

统计因子和倍数的方式

考虑这样一个问题,给定一个数组a1,,an,每个数都大于等于1,且不超过M。且1n,M107

f(x)=ni=1[ai|x],即序列a中有多少数是x的因子。

要求输出f(1),,f(M)

首先我们记c(x)表示xa序列中出现的次数。之后考虑如何解决这个问题。

这个问题有很多做法,最简单的是枚举所有的因子,这样可以给出O(MM)的时间复杂度。

还有一种做法,就是我们仅考虑每个数的所有倍数,并进行统计。这样时间复杂度为O(MlnM)的时间复杂度。

还有一种做法,就是我们考虑所有素数的倍数,并进行统计。这样时间复杂度为O(MlnlnM)

这里我们仅详细讲一下最后一种方式,这种方式我是从这个评论学到的。代码如下:

let primes be all prime of [1, M];
f = g;
for(p in primes) {
    for(i = 1; i * p <= M; i++){
        f[i * p] += f[i];
    }
}

pi表示第i小的素数,很显然时间复杂度为π(M)i=1Mpi,根据素数定理,π(M)MlnM,因此pπ(M)M,可以得出pxxlnx。代入进去可以得到:

π(M)i=1MpiMπ(M)i=21ilniMπ(M)i=21xlnxdxM[lnlnx]π(M)2MlnlnM

因此可以得出时间复杂度为O(MlnlnM)

现在我们考虑算法的具体含义。记fi表示处理完第i个素数后f数组的取值。这时候有f0=cf1(x)=kf0(xpk1)

f2(x)=kf1(xpk2)=kjf0(xpk2pj1)

换言之ft(x)表示x枚举所有i1,,itc(xtj=1pijj)的和。而fπ(M)(x)自然就是所有x的因子和。

我们提到的这个问题是统计因子的,但是统计倍数也可以用类似的做法优化到O(MlnlnM)