约数
定义:$a|b$ 表示 $a$ 整除于 $b$ ($b$ 能被 $a$ 整除),$b$ 为 $a$ 的倍数,$a$ 为 $b$ 的约数
规定 $0$ 是所有非 $0$ 整数的倍数,且对于非 $0$ 整数 $b$ ,$b$ 的约数只有有限个
对于非 $0$ 整数 $b$ ,$\pm1,\pm b$ 是 $b$ 的平凡约数(当 $b=\pm1$ 时,$b$ 只有两个平凡约数),$b$ 的其他约数称为真约数(非平凡约数)
满足性质如下:
- 整数 $b\ne0$,给定的 $d$ 在遍历 $b$ 的全体约数时,$\frac{b}{d}$ 也遍历 $b$ 的全体约数
整数 $b>0$,给定的 $d$ 在遍历 $b$ 的全体正约数时,$\frac{b}{d}$ 也遍历 $b$ 的全体正约数
一般讨论中,我们约定的约数总是指正约数
约数个数定理
对于整数 $n>1$ ,根据唯一分解定理其可以被分解为若干个质因子的连乘积,表示为
$$ n=\prod_{i=1}^{s} p_i^{\alpha _i}=p_1^{\alpha_1}\cdot p_2^{\alpha_2}\cdots p_s^{\alpha_s} $$
那么它的约数个数 $d(n)$ 可以通过下面的表达式得出
$$ d(n)=\prod_{i=1}^s (\alpha_i+1) $$
简单证明如下:
$p_i^{\alpha_i}$ 的因子有 $p_1^0,p_i^1,\cdots,p_i^{\alpha_i}$ 共计 $\alpha_i+1$ 个,递推地计算 $p_{i+1}^{\alpha_{i+1}}$ 及所有项,根据乘法原理得出 $d(n)=\prod_{i=1}^s (\alpha_i+1)$
(若 $p_i^a,p_j^b$ 都是 $n$ 的因子,那么 $p_i^a*p_j^b$ 也是 $n$ 的因子)
线性筛法求约数个数
筛除合数时,分别考虑两种情况
枚举的 $i$ 能被 $p_j$ 整除,则 $p_j$ 一定是 $m$ 的最小质因子,于是递推积累最小质因子的次数 $\alpha_m=\alpha_i+1$
因为 $d(i)=(\alpha_i+1)*\cdots,d(m)=(\alpha_m+1)*\cdots$ 所以 $d(m)$ 由下式计算得出
$$ d(m)=d(i)*\frac{1}{\alpha_m}*(\alpha_m+1) $$
- 若 $i$ 不能被 $p_j$ 整除,则 $i$ 不包含质因子 $p_j$,那么 $\alpha_m=1,d(m)=d(i)*(\alpha_m+1)=2*d(i)$
int p[N],cnt;
bool vis[N];
int a[N],d[N];//a用来记录i的质因子的次数alpha_i,d用来记录i的约数个数
void get_d(int n){
d[1]=1;//定义1的约数个数为1
for (int i=2;i<=n;i++){
if (!vis[i]){//如果当前i为质数
p[++cnt]=i;//存进p数组
a[i]=1;//质数的最小质因子是它本身,且次数为1
d[i]=2;//规定质数的约数个数为2
}
for (int j=1;i*p[j]<=n;j++){//筛除以i为最小质因子的合数
int m=i*p[j];
vis[m]=1;//标记合数
if (i%p[j]==0){//确定只被最小质因子筛除
a[m]=a[i]+1;
d[m]=d[i]/a[m]*(a[m]+1);
break;
}else{
a[m]=1;
d[m]=d[i]*2;
}
}
}
}
约数和定理
有 $n=\prod_{i=1}^sp_i^{\alpha_i}$ ,记 $n$ 的约数和为 $f(n)$ ,满足
$$ f(n)=\prod_{i=1}^s \sum_{j=0}^{\alpha_i} p_i^j $$
简单证明如下:
通过约数个数定理可知,$n$ 的任意一个约数都是在每一个质因子 $p_1^{\alpha_1},p_2^{\alpha_2},\cdots,p_s^{\alpha_s}$ 中,选出这个质因子 $p_i^{\alpha_i}$ 的任意一个约数乘法组合而成
那么,不同的选法共有 $\prod_{i=1}^s (\alpha_i+1)$ 种,即约数个数
那么,它们的和即为
$$ (p_1^0+p_1^1+\cdots+p_1^{\alpha_1})\times(p_2^0+p_1^2+\cdots+p_2^{\alpha_2})\times\cdots\times(p_s^0+p_s^1+\cdots+p_s^{\alpha_s}) $$
可以看作分别计算出了每个质因子的约数的每种情况,再相加
线性筛法求约数和
需要记录每个 $i$ 的最小质因子贡献的累加和,记为 $g_i$,其中 $p_{\gamma}$ 表示 $i$ 的最小质因子
$$ g_i=\sum_{i=0}^{\alpha_i} p_{\gamma}^i $$
筛除合数时,分别考虑两种情况
枚举的 $i$ 能被 $p_j$ 整除,则 $p_j$ 一定是 $m$ 的最小质因子,分别计算 $g_i,g_m$
$$ g_i=\sum_{i=0}^{\alpha_j}p_j^i \ \ ,\ \ g_m=\sum_{i=0}^{\alpha_j+1}p_j^i=g_i*p_j+p_j^0 $$
那么就能从 $f_i$ 递推到 $f_m$
$$ f_i=g_i*\prod_{j}^{j\ne i} g_j\ \ ,\ \ f_m=g_m*\prod_j^{j\ne i} g_j=\frac{f_i}{g_i}*g_m $$
若 $i$ 不能被 $p_j$ 整除,则 $i$ 不包含质因子 $p_j$
$$ g_m=1+p_j\ \ ,\ \ f_m=g_m*f_i $$
int p[N],cnt;
bool vis[N];
int g[N],f[N];//g记录i的最小质因子贡献的累加和,f表示i的约数和
void get_f(int n){
g[1]=f[1]=1;
for (int i=2;i<=n;i++){
if (!vis[i]){
p[++cnt]=i;
g[i]=f[i]=i+1;
}
for (int j=1;i*p[j]<=n;j++){
int m=i*p[j];
vis[m]=1;
if (i%p[j]==0){
g[m]=g[i]*p[j]+1;
f[m]=f[i]/g[i]*g[m];
break;
}else{
g[m]=p[j]+1;
f[m]=f[i]*g[m];
}
}
}
}
评论区(暂无评论)