约数定义
若整数 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 d∣n
唯一数分解定理
对于大于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=p1q1∗p2q2…∗pnqn
其中 p 1 , p 2 … p n p_1,p_2…p_n p1,p2…pn为互不相同的质数。
#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=a∗b,若 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存储所有约数
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 ∗ n 2*\sqrt n 2∗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 ( 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,a−b)=gcd(a,a−b)
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(2∗a,2∗b)=2∗gcd(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)=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;