质因数和约数
1.分解质因数
对于分解质因数这类问题 首先 我们应该知道
- 什么是质因数:质因数,我们可以理解为 对于给定一个数字 n 我们可以用
n = p 1 α 1 ∗ p 2 α 2 ∗ … ⋯ ∗ p x α x ( 1 ) n=p_1^{\alpha_1}*p_2^{\alpha_2}*\ldots\dots*p_x^{\alpha_x} (1) n=p1α1∗p2α2∗…⋯∗pxαx(1)
这个公式 来表示 其中 p为一个质数 α \alpha α可以为0到正无穷的数字 了解了这个我们可以看一下 我们的分解质因数的代码
#include<iostream>
using namespace std;
int n;
void divide(int x)
{
for(int i=2;i<=x/i;i++)
{
if(x%i==0)
{
int s=0;
while(x%i==0)
{
x=x/i;
s++;
}
cout<<i<<" "<<s<<endl;
}
}
if(x>1)
{
cout<<x<<" "<<1<<endl;
}
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++){
int x;
cin>>x;
divide(x);
cout<<endl;
}
return 0;
}
输入
2
6
8
输出
2 1
3 1
2 3
对于这个代码 我们分解质因数的就是从前面到后面遍历所有的数(其实也相当于遍历所有的质数 因为 一个合数肯定可以分解为 多个质数相乘 ),遍历到 n \sqrt{n} n 因为 质因数 不可能比 n \sqrt{n} n 大 不然这两个质因数相乘大于n 矛盾
需要注意的是 在我们的代码当中 传进去的形式参数 x是不断减少的 因为我们分解质因数的过程其实就是 去找上面那个公式(1)当中 的p和 α \alpha α的过程 方程两边同时除以一个数不会影响我们最后的求解
if(x>1)
{
cout<<x<<" "<<1<<endl;
}
对于这段代码的使用 有两种情况 一种是 我们的 x本身就是质数 遍历完 之后没有找到质因数 还有一种就是我们不断减少 我们的x过程中最大的那一个p的系数是1 也就是相当于 最大的那个p就是一个单独的质数 那么这时候和第一种情况相同 。 可以试一下 12的例子 理解会深刻一点
2.试除法求一个数字的约数
约数就是对于一个数 n 所有能被他整除的数都是他的约数
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
vector<int> divide(int x)
{
vector<int > res;
for(int i=1;i<=x/i;i++)
{
if(x%i==0)
{
res.push_back(i);
// 防止出现 i*i=x重复添加
if(x/i!=i)
{
res.push_back(x/i);
}
}
}
sort(res.begin(),res.end());
return res;
}
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
int x;
cin>>x;
auto res=divide(x);
for(auto p:res)
{
cout<<p<<" ";
}
cout<<endl;
}
return 0;
}
输入
2
6
8
输出
1 2 3 6
1 2 4 8
约数我们可以理解 公式(1) 当中 对于每个 α i \alpha_i αi 取0到上界 的不同值的排列组合 这样我们就可以的到所有的 约束的个数 也就是下一个题目。
3.约数的个数
对于约数的个数 在2中已经解释了 约数个数的公式 具体公式如公式2
a
n
s
=
(
α
1
+
1
)
∗
(
α
2
+
1
)
…
…
(
α
k
+
1
)
ans=({\alpha_1+1})*({\alpha_2+1})\ldots\ldots({\alpha_k+1})
ans=(α1+1)∗(α2+1)……(αk+1)
因为 每个
α
\alpha
α可以取 0到
α
\alpha
α的所有的值 所以 有
α
+
1
\alpha+1
α+1个值可以选择 每个都是 那么利用排列组合当中的乘法原则 他们相乘 就可以得到我们的ans。
我们可以看看题目 这个题目就是求给定n个数 求他们的乘积的约数的个数和
我们可以这么理解 乘积也是一个数 也一定是 符合公式(1)的 那么 我们只需要分开来求 成绩的 每个
α
\alpha
α即可 因为
p
α
∗
p
β
=
p
α
+
β
p^\alpha *p^\beta=p^{\alpha+\beta}
pα∗pβ=pα+β
所以 我们 先分开求 然后把他们各自p对应的
α
\alpha
α 加起来 就可以得到最终的
α
\alpha
α
coding:
注意undermap的使用
#include<iostream>
#include<algorithm>
#include<unordered_map>
using namespace std;
const int mod=1e9+7;
unordered_map<int ,int> ps;
void diviede(int x)
{
// 分解质因数的步骤
for(int i=2;i<=x/i;i++)
{
if(x%i==0)
{
while(x%i==0)
{
x=x/i;
ps[i]++;
}
}
}
if(x>1)
{
ps[x]++;
}
}
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
int x;
cin>>x;
diviede(x);
}
long long int ans=1;
for(auto p:ps)
{
ans=ans*(p.second+1);
ans=ans%mod;
}
cout<<ans<<endl;
return 0;
}
输入
3
2
6
8
输出
12
4.约数的和
约数的和其实也是一个公式
a
n
s
=
(
p
1
0
+
p
1
1
+
…
+
p
1
α
1
)
∗
(
p
2
0
+
p
2
1
+
…
+
p
2
α
2
)
∗
…
∗
(
p
k
0
+
p
k
1
+
…
+
p
k
α
k
)
ans=(p_1^0+p_1^1+\ldots+p_1^{\alpha_1})*(p_2^0+p_2^1+\ldots+p_2^{\alpha_2})*\ldots*(p_k^0+p_k^1+\ldots+p_k^{\alpha_k})
ans=(p10+p11+…+p1α1)∗(p20+p21+…+p2α2)∗…∗(pk0+pk1+…+pkαk)
这个公式要理解 我们可以把它展开 发现是 约数个数项多项式的和 每一个 多项式都会是一个 约数 他们相加自然 是所有约数的和 。
coding:
#include<iostream>
#include<algorithm>
#include<unordered_map>
using namespace std;
const int mod=1e9+7;
unordered_map<int ,int> ps;
void diviede(int x)
{
// 分解质因数的步骤
for(int i=2;i<=x/i;i++)
{
if(x%i==0)
{
while(x%i==0)
{
x=x/i;
ps[i]++;
}
}
}
if(x>1)
{
ps[x]++;
}
}
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
int x;
cin>>x;
diviede(x);
}
long long int ans=1;
for(auto p:ps)
{
long long int res=1;
long long int a=p.first;
long long int b=p.second;
// 注意p的0次方 因为 b等于0的时候就不进了
while(b--)
{
res=(res*a+1)%mod;
}
ans=ans*res;
ans=ans%mod;
}
cout<<ans<<endl;
return 0;
}
注意我们 在 在求p的0次方到p的n次方的时候所使用的方法 这里 res表示 这个总和 执行一次 变为 p+1 执行两次 变为 p 2 + p + 1 p^2+p+1 p2+p+1了 依次类推即可 。
5.求最大公约数
直接__gcd()就完事了 然后 这个需要头文件 algorithm 欧几里得算法 太难了QAQ
coding:
#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
int x,y;
cin>>x>>y;
cout<<__gcd(x,y)<<endl;
}
return 0;
}