约数

aa为一个非零整数,bb是一个整数,如果存在一个整数qq ,使得 b=aqb=a*q,那么bb可被aa整除,记作 aba|bbbaa的倍数,aabb的约数

性质

1、如果aba|bbcb|c,那么aca|c

2、aba|baca|c,对任意的整数xxyy,有a(bx+cy)a|(b*x+c*y)

3、aba|b等价于(am)(bm)(a*m)|(b*m),m不为零

4、设整数xxyy满足下式ax+by=1a*x + b * y =1,且ana|nbnb|n,那么(ab)n(a*b)|n

算术基本定理

任何一个大于1的自然数 N,如果

N不为质数,那么N可以唯一分解成有限个质数的乘积

N=p1c1p2c2...pmcmN = p_1^c1p_2^c2...p_m^cm

其中cici都是正整数

试除法求整数x的正约数集合

时间复杂度Onsqrt(n)O(n*sqrt(n))

1
2
3
4
5
6
7
vector<int> res;
int x;
for (int i = 1; i<= x / i; i ++)
if (x % i == 0) {
res.emplace_back(i);
if(i != x / i) res.emplace_back(x/i);
}

倍数法求整数x的正约数集合

设有dnd|n

d = 1,d为1~n所有数的约数,数量为n;

d = 2,d为2,4,6,8……的约数,数量为n2\frac{n}{2};

d = 3,d为3,6,9……的约数,数量为n3\frac{n}{3};

……

d = n,数量为nn\frac{n}{n};

共有

n(1+12+13++1n)=nlognn*(1+\frac{1}{2}+\frac{1}{3}+……+\frac{1}{n}) = n*logn

时间复杂度为O(n*logn)

1
2
3
vector<int> res[N];
for (int i = 1 ; i<= n; i ++)
for ( int j = 1; j <= n/ i; j ++) res[i*j].emplace_back(i);

约数个数

基于算术基本定理

N=p1c1p2c2...pmcmN = p_1^{c1}p_2^{c2}...p_m^{cm}

N的约数

d=p1b1p2b2...pmbmd = p_1^b1p_2^b2...p_m^bm

bibi可以取 [0,ci],共ci+1种取法,约数个数总数为

i=1n(ci+1)\sum_{i=1}^n(ci+1)

https://www.acwing.com/problem/content/description/872/

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <bits/stdc++.h>
#include <unordered_map>
using namespace std;

const int N = 110, mod = 1e9+7;
int t,n;
int main(){
cin>>t;
unordered_map<int,int> q;
long long ans = 1;
while (t--){
cin>>n;
for (int i= 2; i <= n / i; i ++)
if (n % i == 0){
while ( n % i == 0){
n /= i;q[i]++;
}
}
if(n > 1) q[n]++;
}
for (auto i : q) ans = ans*(i.second + 1) % mod;
cout<<ans<<'\n';
}

约数之和

约数和为

(1+p1+p12+...+p1c1)(1+p2+p22+...+p2c2)+...+(1+pm+pm2+...+pmcm)(1 + p_1 +p_1^2 + ...+p_1^{c1})*(1+p_2+p_2^2+...+p_2^{c2}) + ...+(1+p_m+p_m^2+...+p_m^{cm})

N的约数d可以分解成

d=p1b1p2b2...pmbmd = p_1^{b1}p_2^{b2}...p_m^{bm}

约数和公式得到的每一项都是d的形式

倍增法求约数和

1
2
3
4
5
6
7
8
9
vector<int> res[N];
for (int i = 1 ; i<= n; i ++)
for ( int j = 1; j <= n/ i; j ++) res[i*j].emplace_back(i);
for (int i = 1; i<= n; i++){
int ans = 0;
for (int j = 0; j < res[i].size(); j ++) ans += res[i][j];
cout<<ans<<'\n';
}

https://www.acwing.com/problem/content/description/873/

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <iostream>
#include <unordered_map>
using namespace std;

const int N = 110, mod = 1e9+7;
int t,n;
int main(){
cin>>t;
unordered_map<int,int> q;
long long ans = 1;
while (t--){
cin>>n;
for (int i= 2; i <= n / i; i ++)
if (n % i == 0){
while ( n % i == 0){
n /= i;q[i]++;
}
}
if(n > 1) q[n]++;
}
for (auto i : q) {
auto p = i.first, s = i.second;
long long cnt = 1;
while (s--) cnt = (cnt * p + 1) % mod;
ans = ans * cnt % mod;
}
cout<<ans<<'\n';
}

GCD LCM

由算术基本定理可知,整数A=p1a1+p2a2+p3a3+...+pmamA=p_1^{a_1}+p_2^{a_2}+p_3^{a_3}+...+p_m^{a_m},整数B=p1b1+p2b2+p3b3+...+pmbmB=p_1^{b_1}+p_2^{b_2}+p_3^{b_3}+...+p_m^{b_m}

对于AABB的约数d=p10min(a1,b1)+p20min(a2,b2)+p30min(a3,b3)+...+pm0min(am,bm)d=p_1^{0-min(a_1,b_1)}+p_2^{0-min(a_2,b_2)}+p_3^{0-min(a_3,b_3)}+...+p_m^{0-min(a_m,b_m)}

AABB的最大公约数gcd(A,B)=p1min(a1,b1)+p2min(a2,b2)+p3min(a3,b3)+...+pmmin(am,bm)gcd(A,B)=p_1^{min(a_1,b_1)}+p_2^{min(a_2,b_2)}+p_3^{min(a_3,b_3)}+...+p_m^{min(a_m,b_m)}

AABB的最小公倍数

lcm(A,B)=p1max(a1,b1)+p2max(a2,b2)+p3max(a3,b3)+...+pmmax(am,bm)lcm(A,B)=p_1^{max(a_1,b_1)}+p_2^{max(a_2,b_2)}+p_3^{max(a_3,b_3)}+...+p_m^{max(a_m,b_m)}

证得AB=gcd(A,B)lcm(A,B)A*B=gcd(A,B)*lcm(A,B)

如何直观求GCD——辗转相除法

gcd(a,b)=gcd(a(modb),b)gcd(a,b) = gcd(a\pmod b,b)

r(a,b)r(a,b)aabb所有公因数的集合,有gcd(a,b)=max(r(a,b))gcd(a,b)=max(r(a,b))
要证gcd(a,b)=gcd(a,ab)gcd(a,b) = gcd(a,a-b),只需证r(a,b)=r(a,ab)r(a,b) = r(a,a-b)

根据整除的性质dbd|bdcd|c,那么对任意的整数xx,yy,有d(xb+yc)d|(x*b+y*c)

a,ba,b的公因数是a,aba,a-b的公因数,a,ab,aa,a-b,a的公因数是a,ba,b的公因数

证得r(a,b)=r(a,ab)r(a,b)=r(a,a-b),则gcd(a,b)=gcd(a,ab)gcd(a,b) = gcd(a,a-b)