约数定义
若整数nnn除以整数ddd的余数为0,即ddd能够整除nnn,则称ddd为nnn的约数,nnn为ddd的倍数,记作d∣nd|nd∣n
唯一数分解定理
对于大于1的自然数x,可以唯一的分解为
x=p1q1∗p2q2…∗pnqnx=p_1^{q1}*p_2^{q2}…*p_n^{qn}x=p1q1∗p2q2…∗pnqn
其中p1,p2…pnp_1,p_2…p_np1,p2…pn为互不相同的质数。
#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=a∗b,若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存储所有约数
for(int 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 n2∗n个。
倍数法
若要求出1~n的所有数的正约数,试除法复杂度为O(n∗n)O(n*\sqrt n)O(n∗n)还是太慢,反过来考虑,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,a−b)=gcd(a,a−b)
2.对于任意正整数a,b,有gcd(2∗a,2∗b)=2∗gcd(a,b)gcd(2*a,2*b)=2*gcd(a,b)gcd(2∗a,2∗b)=2∗gcd(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)=a∗b/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=k∗b+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;