[数论] 约数

本文深入介绍了整数的约数概念,包括如何判断一个数是否为另一个数的约数,以及如何高效地找到一个数的所有正约数。此外,文章还探讨了唯一数分解定理,展示了如何通过编程实现数的唯一质因数分解。同时,讨论了正约数的个数、总和的计算方法,并提出了倍数法快速找出区间内所有数的正约数。最后,文章提到了最大公因数(gcd)和最小公倍数(lcm)的概念,以及它们之间的关系,并提供了gcd的欧几里得算法实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

约数定义

若整数nnn除以整数ddd的余数为0,即ddd能够整除nnn,则称dddnnn的约数,nnnddd的倍数,记作d∣nd|ndn

唯一数分解定理

对于大于1的自然数x,可以唯一的分解为

x=p1q1∗p2q2…∗pnqnx=p_1^{q1}*p_2^{q2}…*p_n^{qn}x=p1q1p2q2pnqn

其中p1,p2…pnp_1,p_2…p_np1,p2pn为互不相同的质数。

#include <bits/stdc++.h>
#define LL long long
using namespace std;
struct note{
	int sum,cs;
}f[100086];
int tot=0;
bool pd(int x)
{
	for(int i=2;i<=sqrt(x);i++)
	{
		if(x%i==0) return 0;
	}
	return 1;
}
void fenjie(int x)
{
	for(int i=2;i<=sqrt(x);i++)
	{
		if(x%i==0&&pd(i)==1)
		{
			tot++;
			f[tot].sum=i;
			while(x%i==0)
			{
				f[tot].cs++;
				x=x/i;
			}
			if(pd(x)==1&&x!=1)
			{
				tot++;
				f[tot].sum=x;
				f[tot].cs=1;
				return ;
			}
			else if(x==1) return ;
		}
	 } 
}
int main()
{
	int n;
	cin>>n;
	if(pd(n)==1)
	{
		cout<<n<<" "<<"1"<<endl;
		return 0;
	}
	fenjie(n);
	for(int i=1;i<=tot;i++)
	{
		cout<<f[i].sum<<" "<<f[i].cs<<endl;
	}
	return 0;
}

推论

NNN的正约数个数为(∏求积,∑求和)(\prod求积,\sum求和)

(q1+1)∗(q2+1)∗...∗(qm+1)=∏i=1m(ci+1)(q_1+1)*(q_2+1)*...*(q_m+1)=\prod_{i=1}^m (c_i+1)(q1+1)(q2+1)...(qm+1)=i=1m(ci+1)

NNN的所有正约数之和为

(1+p1+p12+...+p1q1)∗...(1+pm+pm2+...+pmcm)=∏i=1m(∑j=0ci(pi)j)(1+p_1+p_1^2+...+p_1^{q1})*...(1+p_m+p_m^2+...+p_m^{c_m})=\prod_{i=1}^{m}(\sum_{j=0}^{c_i}(p_i)^j)(1+p1+p12+...+p1q1)...(1+pm+pm2+...+pmcm)=i=1m(j=0ci(pi)j)

求n的正约数集合

试除法

x=a∗bx=a*bx=ab,若a<=xa<=\sqrt xa<=x,则b>=xb>=\sqrt xb>=x,换句话说,约数总是成对出现的,所以只需扫描i=1i=1i=1~ n\sqrt nn,若i能够整除n,则n/in/in/i也能够整除n,时间复杂度为O(n)O( \sqrt n)O(n)

int m=0,a[100086];//m约数的个数,a存储所有约数
forint i=1;i<=sqrt(n);i++)
{
	if(n%i==0)
	{
		a[++m]=i;
		if(i!=n/i) a[++m]=n/i;
	}
}

推论

一个整数n的约数个数最多为2∗n2*\sqrt n2n个。

倍数法

若要求出1~n的所有数的正约数,试除法复杂度为O(n∗n)O(n*\sqrt n)O(nn)还是太慢,反过来考虑,1~n中以d为约数的数就是d的倍数。

vector<int> a[100086]
for(int i=1;i<=n;i++)
{
	for(int j=1;j<=n/i;j++)
	{
		a[i*j].push_back(i);
	}
}
for(int i=1;i<=n;i++)
{
	for(int j=0;j<a[i].size();j++)
	{
		cout<<a[i][j]<<" ";
	}
	cout<<endl;
}

其复杂度为O(nlogn)O(n logn)O(nlogn)

更相减损法

1.对于任意正整数a,b,有gcd(a,b)=gcd(b,a−b)=gcd(a,a−b)gcd(a,b)=gcd(b,a-b)=gcd(a,a-b)gcd(a,b)=gcd(b,ab)=gcd(a,ab)

2.对于任意正整数a,b,有gcd(2∗a,2∗b)=2∗gcd(a,b)gcd(2*a,2*b)=2*gcd(a,b)gcd(2a,2b)=2gcd(a,b)

gcd及lcm定义

对于两个正整数a,b,存在最大的x使得a%x== 0 ,b%x==0,

那么我们称x为a,b的最大公因数,即gcd(a,b)=xgcd(a,b)=xgcd(a,b)=x.

若存在一个最小的正整数y,使得y%a== 0,y%b==0,则称y为a,b的最小公倍数,即lcm(a,b)=ylcm(a,b)=ylcm(a,b)=y.

gcd和lcm还满足lcm(a,b)=a∗b/gcd(a,b)lcm(a,b)=a*b/gcd(a,b)lcm(a,b)=ab/gcd(a,b)

证明

对于gcd(a,b)的计算方法,我们可以采用欧几里得算法gcd(a,b)=gcd(b,a%b)。

证明过程如下:

假设 a%b=r,既有a=k∗b+r(k为常数)a=k*b+r(k为常数)a=kb+r(k),设d为a,b的公约数,那么就有a%d== 0,b%d== 0,所以r=a-kb,故r%d== 0,故d也是b,a%b的公约数,假设d是b,a%b的公约数,那么 b%d== 0,d%(a-kb)== 0,故d%a==0,因此d也是a,b的公因数。

所以a,b的公因数等于b,a%b的公因数。

int gcd(int a,int b)
{
	if(b) return gcd(b,a%b);
	else return a;
}

PS:其实在C++中可以用__gcd(a,b)函数来求出a,b的最大公因数。

int a,b;
cin>>a>>b;
cout<<__gcd(a,b)<<endl;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值