筛法求约数个数、约数和定理

数论基础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\) ,根据唯一分解定理其可以被分解为若干个质因子的连乘积,表示为

\[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];
			}
		}
	}
}
posted @ 2025-05-21 19:23  才瓯  阅读(32)  评论(0)    收藏  举报