约数个数以及约数和

如何求约数个数以及约数和

  • 1 ∼ n 1 \sim n 1n的约数个数
    • 参考代码
  • 约数和
    • 证明过程:
    • 过程分析
    • 参考代码

1 ∼ n 1 \sim n 1n的约数个数

已知一个数n可以表示为 n = ∏ i = 1 k p i a i n=\prod_{i=1}^k {p_i^{a_i}} n=i=1kpiai
对于你从中选取若干的 p i p_i pi乘起来,就是n的一个因子,对于每个 p i p_i pi你都有 a i + 1 a_i+1 ai+1种选择,我们将n的约数个数记为 d ( n ) d(n) d(n),所以会有
d ( n ) = ∏ i = 1 k ( a i + 1 ) d(n) = \prod_{i=1}^k(a_i+1) d(n)=i=1k(ai+1)

对于 2 ∼ n 2 \sim n 2n的每一个数 i i i,使用线性筛时知道 v [ i ] v[i] v[i]是确定 i i i的最小质因子

  • 如果 i i i是质数,那么它的因子就只有两个, 1 和 i 1和i 1i,所以 d ( i ) = 2 d(i)=2 d(i)=2
  • 如果 i i i合数,设 p p p为确定 i i i的最小质因子,也就是说,可以将 i i i表示为 i = p ∗ k i=p*k i=pk
    • 如果 k   m o d   p = 0 k \bmod p =0 kmodp=0,那么 k k k就含有和 i i i一样的所有质因子,只是最小质因子 p p p的指数不一样, a ( i ) = a ( k ) + 1 a(i)=a(k)+1 a(i)=a(k)+1,所以我们可以通过将 k k k p p p的指数变成 0 0 0,再乘上 i i i p p p的指数,就可以得到 d ( i ) d(i) d(i)了,所以我们需要使用一个数组 a a a来记录最小质因子的指数,就可以得到一个推导式 d ( i ) = d ( k ) a ( k ) + 1 ∗ ( a ( i ) + 1 ) d(i)=\frac{d(k)}{a(k)+1} * (a(i)+1) d(i)=a(k)+1d(k)(a(i)+1)
    • 如果 k   m o d   p ≠ 0 k \bmod p \ne0 kmodp=0,那么就相当于 i i i k k k多了一个质数 p p p,并且这个是 i i i的最小质因子,指数为1,即 a ( i ) = 1 a(i)=1 a(i)=1,然后直接乘上对 p p p的选择即可 d ( i ) = d ( k ) ∗ ( a ( i ) + 1 ) d(i)=d(k)*(a(i)+1) d(i)=d(k)(a(i)+1)

参考代码

#include
using namespace std;
using ll =long long ;

const int N=1e6;
int p[N],v[N],a[N],d[N];
int cnt;
int phi[N];



void get_d(int n){
	
	d[1]=1;
	for(int i=2;i<=n;i++){
		if(!v[i]){
			v[i]=i;
			a[i]=1;
			d[i]=2;
			p[++cnt]=i;
		}
		for(int j=1;j<=cnt;j++){
			if(p[j]>i||p[j]>n/i)break;
			int m=i*p[j];
			v[m]=p[j];
			if(i%p[j]==0){
				a[m]=a[i]+1;
				d[m]=d[i]/(a[i]+1)*(a[m]+1);
			}
			else{
				a[m]=1;
				d[m]=d[i]*2;
			}
		}
	}
}
int main(){
	int n;
	cin>>n;
	get_d(n);
	for(int i=1;i<=n;i++)
		cout<<d[i]<<' ';
	cout<<endl;
}

约数和

对于你从中选取若干个 p i p_i pi的乘积,就是n的一个因子,所有的因子和,就相当于对于每个质数 p i p_i pi的选择的和的连乘,记为 f ( n ) f(n) f(n),也就是说
f ( n ) = ∏ i = 1 k ∑ j = 0 a i p i j f(n) = \prod_{i=1}^k \sum_{j=0}^{a_i} p_i^j f(n)=i=1kj=0aipij

证明过程:

  • 如果n只由一个质数 p p p构成,其指数为 a a a,我们知道对于每个约数,就是对这个质数 p p p的选择,总共会有 a + 1 a+1 a+1种选择,分别是 1 , p 1 , p 2 , p 3 ⋯ p a 1,p^1,p^2, p^3 \cdots p^a 1,p1,p2,p3pa,这些都是 n n n的因子,所以 n n n的约数和为 f ( n ) = 1 + p 1 + p 2 + p 3 + ⋯ + p a f(n)=1+p^1+p^2+p^3+ \cdots+p^a f(n)=1+p1+p2+p3++pa
  • 如果由2个质数组成,对于每个质数 p 1 p_1 p1的每一种选择,另一个质数的选择会是 1 , p 2 1 , p 2 2 , p 2 3 ⋯ p 2 a 2 1,p_2^1,p_2^2, p_2^3 \cdots p_2^{a_2} 1,p21,p22,p23p2a2,对 p 1 p_1 p1的一种选择的约数和为
    p 1 j ∗ ( 1 + p 2 1 + p 2 2 + p 2 3 + ⋯ + p 2 a 2 ) p_1^j*(1+p_2^1+p_2^2+ p_2^3+ \cdots +p_2^{a_2}) p1j(1+p21+p22+p23++p2a2)
    对于 p 1 p_1 p1的每一种选择提取相同的公因式 ( 1 + p 2 1 + p 2 2 + p 2 3 + ⋯ + p 2 a 2 ) (1+p_2^1+p_2^2+ p_2^3+ \cdots +p_2^{a_2}) (1+p21+p22+p23++p2a2),就为
    ( 1 + p 1 1 + p 1 2 + p 1 3 + ⋯ + p 1 a 2 ) ∗ ( 1 + p 2 1 + p 2 2 + p 2 3 + ⋯ + p 2 a 2 ) (1+p_1^1+p_1^2+ p_1^3+ \cdots +p_1^{a_2})*(1+p_2^1+p_2^2+ p_2^3+ \cdots +p_2^{a_2}) (1+p11+p12+p13++p1a2)(1+p21+p22+p23++p2a2)
  • 如果由多个质数组成,就像两个质数的情况一样,一步一步拆分每个质数的选择的情况,就可以获得约数和的公式:
    f ( n ) = ∏ i = 1 k ∑ j = 0 a i p i j f(n) = \prod_{i=1}^k \sum_{j=0}^{a_i} p_i^j f(n)=i=1kj=0aipij

过程分析

我们设 g ( i ) g(i) g(i)为数 i i i的最小质因子的各项指数的和(幂和),即 g ( i ) = p 0 + p 1 + p 2 + ⋯ p k g(i)=p^0+p^1+p^2+ \cdots p^k g(i)=p0+p1+p2+pk
对于 2 ∼ n 2 \sim n 2n的每一个数 i i i,使用线性筛时知道 v [ i ] v[i] v[i]是确定 i i i的最小质因子

  • 如果 i i i是质数,那么它的约数和就是, i + 1 i+1 i+1,所以 f ( i ) = i + 1 f(i)=i+1 f(i)=i+1
  • 如果 i i i合数,设 p p p为确定 i i i的最小质因子,也就是说,可以将 i i i表示为 i = p ∗ k i=p*k i=pk
    • 如果 k   m o d   p = 0 k \bmod p =0 kmodp=0,那么 k k k就含有和 i i i一样的所有质因子,只是最小质因子 p p p的指数不一样, g ( i ) = g ( k ) ∗ p + 1 g(i)=g(k)*p+1 g(i)=g(k)p+1,所以我们可以通过将 k k k p p p的指数变成 0 0 0,再乘上 g ( i ) g(i) g(i),就可以得到 f ( i ) f(i) f(i)了,就可以得到一个推导式 f ( i ) = f ( k ) g ( k ) ∗ g ( i ) f(i)=\frac{f(k)}{g(k)} * g(i) f(i)=g(k)f(k)g(i)
    • 如果 k   m o d   p ≠ 0 k \bmod p \ne0 kmodp=0,那么就相当于 i i i k k k多了一个质数 p p p,并且这个是 i i i的最小质因子,指数为1,即 g ( i ) = p 0 + p 1 g(i)=p^0+p^1 g(i)=p0+p1,然后直接乘上即可 f ( i ) = f ( k ) ∗ g ( i ) f(i)=f(k)*g(i) f(i)=f(k)g(i)

参考代码

#include
using namespace std;
using ll =long long ;

const int N=1e6;
int p[N],v[N],g[N],f[N];// g[i]: 当前质因子的幂和,f[i]: 约数和
int cnt;


void get_dsum(int n){
	f[1]=1;
	for(int i=2;i<=n;i++){
		if(!v[i]){
			v[i]=i;
			g[i]=i+1;
			f[i]=i+1;
			p[++cnt]=i;
		}
		for(int j=1;j<=cnt;j++){
			if(p[j]>i||p[j]>n/i)break;
			int m=i*p[j];
			v[m]=p[j];
			if(i%p[j]==0){
				g[m]=g[i]*p[j]+1;
				f[m]=f[i]/g[i]*g[m];
			}
			else{
				g[m]=p[j]+1;
				f[m]=f[i]*g[m];
			}
		}
	}
}
int main(){
	int n;
	cin>>n;
	get_dsum(n);
	for(int i=1;i<=n;i++)
		cout<<f[i]<<' ';
	cout<<endl;
}

你可能感兴趣的:(约数个数以及约数和)