[数论] 约数

约数定义

若整数 n n n除以整数 d d d的余数为0,即 d d d能够整除 n n n,则称 d d d n n n的约数, n n n d d d的倍数,记作 d ∣ n d|n dn

唯一数分解定理

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

x = p 1 q 1 ∗ p 2 q 2 … ∗ p n q n x=p_1^{q1}*p_2^{q2}…*p_n^{qn} x=p1q1p2q2pnqn

其中 p 1 , p 2 … p n p_1,p_2…p_n p1,p2pn为互不相同的质数。

#include 
#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;
}

推论

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

( q 1 + 1 ) ∗ ( q 2 + 1 ) ∗ . . . ∗ ( q m + 1 ) = ∏ i = 1 m ( c i + 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)

N N N的所有正约数之和为

( 1 + p 1 + p 1 2 + . . . + p 1 q 1 ) ∗ . . . ( 1 + p m + p m 2 + . . . + p m c m ) = ∏ i = 1 m ( ∑ j = 0 c i ( p i ) 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 ∗ b x=a*b x=ab,若 a < = x a<=\sqrt x a<=x ,则 b > = x b>=\sqrt x b>=x ,换句话说,约数总是成对出现的,所以只需扫描 i = 1 i=1 i=1~ n \sqrt n n ,若i能够整除n,则 n / i n/i n/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 ∗ n 2*\sqrt n 2n 个。

倍数法

若要求出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 ( n l o g n ) O(n logn) O(nlogn)

更相减损法

1.对于任意正整数a,b,有 g c d ( a , b ) = g c d ( b , a − b ) = g c d ( 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,有 g c d ( 2 ∗ a , 2 ∗ b ) = 2 ∗ g c d ( 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的最大公因数,即 g c d ( a , b ) = x gcd(a,b)=x gcd(a,b)=x.

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

gcd和lcm还满足 l c m ( a , b ) = a ∗ b / g c d ( 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;

你可能感兴趣的:(数论)