除数函数 d ( n ) d(n) d(n)
定义:除数函数 d ( n ) d(n) d(n) 是一个算术函数,用于计算正整数 n n n 的正约数个数。
例如 d ( 6 ) = 4 d(6) = 4 d(6)=4, 因为 1 , 2 , 3 , 6 1, 2, 3, 6 1,2,3,6 都是它的约数。
公式
① 若 n = p 1 a 1 ∗ p 2 a 2 ∗ . . . ∗ p k a k n = p_1 ^ {a_1}*p_2 ^ {a_2}*...*p_k ^ {a_k} n=p1a1∗p2a2∗...∗pkak, 其中 p i p_i pi 为质数,则 d ( n ) = ( a 1 + 1 ) ∗ ( a 2 + 1 ) ∗ . . . ∗ ( a k + 1 ) d(n)=(a_1+1)*(a_2+1)*...*(a_k+1) d(n)=(a1+1)∗(a2+1)∗...∗(ak+1)
这一点很好理解,将 n n n 分解质因数后,每个质因子都有 a i + 1 a_i + 1 ai+1 种取法(可以不取,即 0 0 0 个),做一个乘法原理,即为 n n n 的约数个数
求解 d(n)
一、求解单个值
设 n = a ∗ b , a < = b n=a*b, a <= b n=a∗b,a<=b, 则有 a ≤ n a \leq \sqrt{n} a≤n , 所以我们只需要枚举 n \sqrt{n} n 内的约数 a a a, 大于 n \sqrt{n} n 的约数可以通过 n a \frac{n}{a} an 得到。注意一下,当 a = b = n a=b=\sqrt{n} a=b=n 时,别重复计数。时间复杂度 O ( n ) O(\sqrt{n}) O(n)
int dn = 0;
for (int i = 1; i*i <= n; i++) {
if (n % i == 0) {
dn += 2;
if (i * i == n) dn--;
}
}
二、求解 d ( 1 ) ∼ d ( n ) d(1) \sim d(n) d(1)∼d(n)
可以使用线性筛求解, 时间复杂度 O ( n ) O(n) O(n)
// 用 d[i] 表示 i 的约数个数,num[i] 表示 i 的最小质因子出现次数
void calc_dn()
{
d[1] = 1;
for (int i = 2; i < N; i++) {
if (!flag[i]) flag[i] = 1, prime[++lp] = i, d[i] = 2, num[i] = 1;
for (int j = 1; j <= lp && i * prime[j] < N; j++) {
flag[prime[j] * i] = 1;
if (i % prime[j] == 0) {
num[i * prime[j]] = num[i] + 1;
d[i * prime[j]] = d[i] / num[i * prime[j]] * (num[i * prime[j]] + 1);
break;
}
else {
num[i * prime[j]] = 1;
d[i * prime[j]] = d[i] * 2;
}
}
}
}
除数函数的上界
感兴趣可以自己看上述论文,这里给出结论:
log d ( n ) < 1.066 log n log log n , n ≥ 3 \log{d(n)} < 1.066\frac{\log{n}}{\log{\log{n}}}, n \geq 3 logd(n)<1.066loglognlogn,n≥3
大多数人关心的应该是具体的数值,下边给出:
① 1 0 9 10^9 109 以内, d ( n ) ≤ 1344 d(n) \leq 1344 d(n)≤1344
② 2 31 − 1 2^{31}-1 231−1 以内, d ( n ) ≤ 1600 d(n) \leq 1600 d(n)≤1600
③ 1 0 18 10^{18} 1018 以内, d ( n ) ≤ 103680 d(n) \leq 103680 d(n)≤103680
④ 2 63 − 1 2^{63}-1 263−1 以内, d ( n ) ≤ 161280 d(n) \leq 161280 d(n)≤161280
参考:除数函数的渐近上界?
约数和
咕咕咕