文章目录
试除法求一个数的所有约数
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)