约数个数、约数之和、约数

试除法求一个数的所有约数

vector<int> get_divisors(int n) //求n的约数 
{
	vector<int> res;
	
	for(int i=1; i<=n/i; i++)
	   if(n%i == 0)
	   {
	   	 res.push_back(i);
	   	 if(i != n/i) res.push_back(n/i); //比如25的约数5只用存一个 
	   }
	sort(res.begin(),res.end());
	return res;   
}

求约数个数

约数个数定理:
在这里插入图片描述
定理证明:
首先,n 可以分解质因数:n=p1a1 * p2a2 * p3a3 pkak,(其中 pi 为质数)。

由约数定义可知,p1a1的约数有:p10、p11、p12…p1a1,共 (a1+1) 个,同理,p2a2的约数有 (a2+1) 个…pkak的约数有 (ak+1) 个。

根据乘法原理,n 的约数的个数就是(a1+1)(a2+1)(a3+1)…(ak+1)

模板如下:
题目大致意思是给出 n 个数,求这 n 个数乘积的约数个数,答案对109+7取模。

#include<iostream>
#include<algorithm>
#include<map>
using namespace std;
const int mod=1e9+7;

int main()
{
	int n;
	cin>>n;
	
	map<int,int> primes;
	while(n--)
	{
		int x;
		cin>>x;
		
		for(int i=2; i<=x/i; i++)
		   while(x%i == 0)
		   {
		   	 x/=i;
		   	 primes[i]++; //primes的下标是质数,存的值是这个质数的指数
		   }
		if(x>1) primes[x]++;   //x是大于sqrt(x)的那个质数 
	}
	long long res=1;
	for(map<int,int>::iterator it=primes.begin(); it!=primes.end(); it++)
	 res=res*(it->second+1)%mod;
	cout<<res<<endl; 
	 
}

求约数之和

约数之和定理:

对于一个大于1正整数n可以分解质因数:n=p1a1 * p2a2 * p3a3 pkak,
则由约数个数定理可知n的正约数有(a1+1)(a2+1)(a3+1)…(ak+1)个,
那么n的(a1+1)(a1+1)(a3+1)…(ak+1)个正约数的和为:
f(n)=(p10+p11+p12+…p1a1)*(p20+p21+p22+…p2a2) * … *(pk0+pk1+pk2+…pkak

定理证明:
首先,n 可以分解质因数:n=p1a1 * p2a2 * p3a3 pkak,(其中 pi 为质数)。

可知p1a1的约数有:p10, p11, p12…p1a1

同理可知,pkak的约数有:pk0, pk1, pk2…pkak

实际上n的约数是在p1a1、p2a2、…、pkak每一个的约数中分别挑一个相乘得来。

可知共有(a1+1)(a1+1)(a3+1)…(ak+1)种挑法,即约数的个数。

由乘法原理可知它们的和为f(n)=(p10+p11+p12+…p1a1)*(p20+p21+p22+…p2a2) * … *(pk0+pk1+pk2+…pkak

模板如下:

题目大致意思是给出 n 个数,求这 n 个数乘积的约数之和,答案对109+7取模。

#include<iostream>
#include<algorithm>
#include<map>
using namespace std;
const int mod=1e9+7;

int main()
{
	int n;
	cin>>n;
	
	map<int,int> primes;
	while(n--)
	{
		int x;
		cin>>x;
		
		for(int i=2; i<=x/i; i++)
		   while(x%i == 0)
		   {
		   	 x/=i;
		   	 primes[i]++;
		   }
		if(x>1) primes[x]++;   //x是大于sqrt(x)的那个质数 
	}
	long long res=1;
	for(map<int,int>::iterator it=primes.begin(); it!=primes.end(); it++)
	{
		int p=it->first,a=it->second;
		long long t=1;
		while(a--) t=(t*p+1)%mod;
		res=res*t%mod;
	}
	cout<<res<<endl; 	 
}

解释一下这句: while(a- -) t=(t*p+1)%mod;

循环第一次:t=p+1
循环第二次:t=p2+p+1
循环第三次:t=p3+p2+p+1

循环第a次:t=p0+p1+p2+…pa

当然这只是算出了(p10+p11+p12+…p1a1),我们还要算p2、p3、…、pk并相乘


欧几里得算法

也叫辗转相除法,用于求两个数的最大公约数

int gcd(int a,int b)
{
    return b ? gcd(b, a % b) : a;	
} 

b为0时,最大公约数就是a,0可以整除任何数
不为0时,最大公约数就是gcd(b, a % b)

发布了107 篇原创文章 · 获赞 199 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/wmy0217_/article/details/105174148