约数定义: 若整数 n n n除以整数 d d d的余数为0,即 d d d能整除 n n n,则称 d d d是 n n n的约数, n n n是 d d d的倍数,记为 d ∣ n d\ | \ n d ∣ n 。
一、整除的性质
设 a , b a,b a,b是两个正整数,且 b ! = 0 b != 0 b!=0,则存在唯一的整数 q q q和 r r r,使得:
a = q b + r , ( 0 ≤ r < b ) a=qb+r,(0\leq r<b) a=qb+r,(0≤r<b)
这个式子叫做带余除法,并记余数 r = a m o d b r = a\ mod\ b r=a mod b。
整除具有如下性质:
- 若 a ∣ b a\ |\ b a ∣ b且 a ∣ c a\ | \ c a ∣ c,则 ∀ x , y , \forall x,y, ∀x,y,有 a ∣ ( x b + y c ) {a|(xb+yc)} a∣(xb+yc)。
- 若 a ∣ b a\ |\ b a ∣ b且 b ∣ c b\ | \ c b ∣ c,则 a ∣ c a\ | \ c a ∣ c
- 设 m ! = 0 m \ != 0 m !=0,则当且仅当 m a ∣ m b ma|mb ma∣mb时, a ∣ b a\ |\ b a ∣ b
- 若 a ∣ b a\ |\ b a ∣ b且 b ∣ a b\ | \ a b ∣ a, a = ± b a=\pm b a=±b
二、约数
1.算术基本定理(唯一分解定理)的推论
在算术基本定理中,若正整数 N N N被唯一分解为 N = p 1 c 1 p 2 c 2 . . . p m c m N= p_{1}^{c_1} p_{2}^{c_2}... p_{m}^{c_m} N=p1c1p2c2...pmcm,其中 c i c_i ci都是正整数, p i p_i pi都是质数,且满足 p 1 < p 2 < . . . < p m p_1<p_2<...<p_m p1<p2<...<pm,则 N N N的正约数集合可写作:
{ p 1 b 1 p 2 b 2 . . . p m b m } , 其 中 0 ≤ b i ≤ c i \{p_1^{b_1}p_2^{b_2}...p_m^{b_m}\},其中0\leq b_i\leq c_i {
p1b1p2b2...pmbm},其中0≤bi≤ci
N N N的正约数个数为( ∏ \prod ∏表示连乘)
( c 1 + 1 ) ∗ ( c 2 + 1 ) ∗ . . . ∗ ( c m + 1 ) = ∏ i = 1 m ( c i + 1 ) (c_1+1)*(c_2+1)*...*(c_m+1)=\displaystyle\prod^m_{i=1} (c_i+1) (c1+1)∗(c2+1)∗...∗(cm+1)=i=1∏m(ci+1)
N N N的所有正约数的和为
( 1 + p 1 + p 1 2 + . . . + p 1 c 1 ) ∗ ( 1 + p 2 + p 2 2 + . . . + p 2 c 2 ) ∗ . . . ∗ ( 1 + p m + p m 2 + . . . + p m c m ) = ∏ i = 1 m ( ∑ j = 0 c i ( p i ) j ) (1+ p_{1} +p_{1}^{2} +...+p_{1}^{c_1})*(1+ p_{2} +p_{2}^{2} +...+p_{2}^{c_2})*...*(1+ p_{m} +p_{m}^{2} +...+p_{m}^{c_m})=\displaystyle\prod^m_{i=1} (\displaystyle\sum^{c_i}_{j=0}(p_i)^j) (1+p1+p12+...+p1c1)∗(1+p2+p22+...+p2c2)∗...∗(1+pm+pm2+...+pmcm)=i=1∏m(j=0∑ci(pi)j)
//使用算术基本定理求质因子代码
//prime数组是之前用筛法筛出的质数数组。
void divide(ll n)
{
int len = prime.size();
int cnt = 0;
for(int i = 0; i < len; i++)
{
if(n % prime[i] == 0)
{
p[++cnt] = prime[i];
c[cnt] = 0;
while(n % prime[i] == 0 && n > 1)
{
n /= prime[i];
c[cnt]++;
}
}
printf("p = %d c = %d\n",p[cnt],c[cnt]);
if(n == 1)
break;
}
//如果遍历到了1e6的素数,n还没有变为1,那么剩下的n一定是一个素数。(前提,n<1e12)
if(n > 1){
p[++cnt] = n,c[cnt] = 1;
}
}
2.求N的正约数集合——试除法
若 d ≥ N d\geq \sqrt{N} d≥N是 N N N的约数,则 N / d ≤ N N/d\leq \sqrt{N} N/d≤N也是 N N N的约数。换言之,约数总是成对出现的(除了对于完全平方数, N \sqrt{N} N会单独出现)。
因此,只需要扫描 d = 1 ~ N d=1~\sqrt{N} d=1~N,尝试 d d d能否整除 N N N,若能整除,则 N / d N/d N/d也是 N N N的约数。时间复杂度 O ( N ) O(\sqrt{N}) O(N)。
//试除法函数
int f[1600];
void divide(int n){
m = 0;
for(int i = 2; i * i <= n; i++){
if(n % i == 0){
f[++m] = i;
if(i * i != n) f[++m] = n/i;
}
}
}
试除法的推论
一个整数 N N N的约数个数的上界为 2 N 2\sqrt{N} 2N。
3.求1~N每个数的正约数集合——倍数法
若用"试除法"分别求出 1 ~ N 1~N 1~N每个数的正约数集合,时间复杂度过高,为 O ( N N ) O(N\sqrt{N}) O(NN)。可以反过来考虑,对于每个数 d d d, 1 ~ N 1~N 1~N中以 d d d为约数的数就是 d d d的倍数 d , 2 d , 3 d , . . . ⌊ N / d ⌋ ∗ d d,2d,3d,...\lfloor N/d\rfloor *d d,2d,3d,...⌊N/d⌋∗d。以下程序采用"倍数法"求出 1 ~ N 1~N 1~N每个数的正约数集合:
//求1~N每个数的正约数集合——倍数法
vector<int> f2[500010];
void multiple(int n) {
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n/i; j++)
f2[i*j].push_back(i);
}
倍数法的推论
1 ~ N 1~N 1~N每个数的约数个数的总和大约为 N l o g N NlogN NlogN
【例题1】BZOJ 1053 反素数
题意:
如果一个大于等于 1 的正整数 n,满足所有小于 n 且大于等于 1 的所有正整数的约数个数都小于 n 的约数个数,则 n 是一个反素数。譬如:1,2,4,6,12,24,它们都是反素数。
现给定一个数 N ( 1 ≤ n ≤ 2 ∗ 1 0 9 ) N(1\leq n \leq2*10^9) N(1≤n≤2∗109),请你计算不大于 N的最大反素数。
思路:
设 g ( x ) g(x) g(x)为 x x x的约数个数。
- 引理1: 1 ~ N 1~N 1~N中最大的反素数就是,其中约数个数最多的数中最小的一个。
证明: 设 m m m是 1 ~ N 1~N 1~N中约数个数最多的数中最小的一个。根据 m m m的定义, m m m显然满足: Ⅰ. ∀ x < m , g ( x ) < g ( m ) \forall x< m,g(x)<g(m) ∀x<m,g(x)<g(m) Ⅱ. ∀ x > m , g ( x ) ≤ g ( m ) \forall x > m,g(x)\leq g(m)