筛法求约数个数、约数和定理
数论基础F
约数
定义:\(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\) ,根据唯一分解定理其可以被分解为若干个质因子的连乘积,表示为
那么它的约数个数 \(d(n)\) 可以通过下面的表达式得出
简单证明如下:
\(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)\) ,满足
简单证明如下:
通过约数个数定理可知,\(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)\) 种,即约数个数
那么,它们的和即为
可以看作分别计算出了每个质因子的约数的每种情况,再相加
线性筛法求约数和
需要记录每个 \(i\) 的最小质因子贡献的累加和,记为 \(g_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];
}
}
}
}