约数
试除法求约数
Code
//获取一个数的所有约数,从小到大
vector<int> get_divisors(int n) {
vector<int> res;
for(int i = 1; i <= n / i; i++) { //最多只要枚举到sqrt(n)
if(n % i == 0) {
res.push_back(i);
if(i != n / i) res.push_back(n / i); //把它成对的约数push进vector
}
}
sort(res.begin(), res.end());
return res;
}
求一个数所有约数的个数
N = p 1 α 1 p 2 α 2 . . . p n α n N=p_1^{\alpha_1}p_2^{\alpha_2}...p_n^{\alpha_n} N=p1α1p2α2...pnαn ,其中, p p p 是 N N N 的质因数, α i \alpha_i αi 是约数的指数,则一个数所有约数的个数为
a n s = ( a 1 + 1 ) ( a 2 + 1 ) ( a 3 + 1 ) . . . ( a n + 1 ) ans=(a_1+1)(a_2+1)(a_3+1)...(a_n+1) ans=(a1+1)(a2+1)(a3+1)...(an+1)
理由是,任何一个约数 d d d 可以表示成 p β 1 p β 2 p β 3 . . . p β n , 0 ≤ β i ≤ α i p^{β_1}p^{β_2}p^{β_3}...p^{β_n}\ ,0≤β_i≤α_i pβ1pβ2pβ3...pβn ,0≤βi≤αi ,每一项的 β i \beta_i βi 如果不同,那么约数 d d d 就不相同(算数基本定理,每个数的因式分解是唯一的)所以, n n n 的约数就跟 β i β_i βi 的选法是一一对应的 β 1 β_1 β1 一共有 0 ∼ α 1 0∼α_1 0∼α1 种选法, β 2 β_2 β2 一共有 0 ∼ α 2 0∼α_2 0∼α2 种选法 → \to → β k β_k βk 一共有 0 ∼ α k 0∼α_k 0∼αk 种选法,根据乘法原理,一共有 a n s ans ans 个约数
一个小结论: i n t int int 范围内,约数最多的一个数的约数大概是1500个
Code
ll divnum(ll x) {
unordered_map<ll, ll> primes;
for(int i = 2; i <= x / i; i++) {
while(x % i == 0) {
x /= i;
primes[i]++;
}
}
if(x > 1) primes[x]++;
ll res = 1;
for(auto prime : primes) res = res * (prime.second + 1);
return res;
}
练习
约数之和
N = p 1 α 1 p 2 α 2 . . . p n α n N=p_1^{\alpha_1}p_2^{\alpha_2}...p_n^{\alpha_n} N=p1α1p2α2...pnαn ,其中, p p p 是 N N N 的质因数, α i \alpha_i αi 是约数的指数,则一个数的所有约数之和为
a n s = ( p 1 0 + p 1 1 + p 1 2 + . . . p 1 α 1 ) × ( p 2 0 + p 2 1 + p 2 2 + . . . p 2 α 2 ) × ( p 3 0 + p 3 1 + p 3 2 + . . . p 3 α 3 ) × . . . × ( p k 0 + p k 1 + p k 2 + . . . p k α k ) ans=(p_1^{0}+p_1^{1}+p_1^{2}+...p_1^{\alpha_1})\times(p_2^{0}+p_2^{1}+p_2^{2}+...p_2^{\alpha_2})\times (p_3^{0}+p_3^{1}+p_3^{2}+...p_3^{\alpha_3})\times...\times(p_k^{0}+p_k^{1}+p_k^{2}+...p_k^{\alpha_k}) ans=(p10+p11+p12+...p1α1)×(p20+p21+p22+...p2α2)×(p30+p31+p32+...p3α3)×...×(pk0+pk1+pk2+...pkαk)
使用乘法分配率展开,每一项都是约数
如何计算每一个项呢
while(a--) t = (t * p + 1) % mod;
通过对计算步骤的复现可以知道
当执行 1 次时, t = ( p + 1 ) t=(p+1) t=(p+1)
当执行 2 次时, t = ( p + 1 ) × p + 1 = p 2 + p + 1 t=(p+1)\times p +1=p^2+p+1 t=(p+1)×p+1=p2+p+1
当执行 3 次时, t = p 2 + p + 1 × p + 1 = p 3 + p 2 + p + 1 t=p^2+p+1\times p+1=p^3+p^2+p+1 t=p2+p+1×p+1=p3+p2+p+1
这样可以知道,执行 α k \alpha_k αk 次之后,得到的式子就是
t = p 1 0 + p 1 1 + p 1 2 + . . . p 1 α 1 t=p_1^{0}+p_1^{1}+p_1^{2}+...p_1^{\alpha_1} t=p10+p11+p12+...p1α1
Code
给定 n n n 个正整数 a i a_i ai ,请你输出这些数的乘积的约数之和,答案对 1 0 9 + 7 10^9+7 109+7 取模。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const long long mod = 1e9 + 7;
int main() {
int T;
scanf("%d", &T);
unordered_map<int, int> primes;//存储分解完成的质数
while(T--) {
int x;
scanf("%d", &x);
//分解每个质数
for(int i = 2; i <= x / i; i++) {
while(x % i == 0) {
x /= i;
primes[i]++;
}
}
if(x > 1) primes[x]++;
}
ll res = 1;
for(auto prime : primes) {
int p = prime.first, a = prime.second; //p表示约数 a表示约数的指数
ll t = 1;
while(a--) t = (t * p + 1) % mod;//根据公式计算每一项
res = res * t % mod;
}
printf("%lld\n", res);
return 0;
}
求最大公约数
使用
__gcd(a,b);