文章目录
- 1.质数
- 1.1质数的判定---试除法
- 1.2分解质因数---试除法
- 1.3筛质数
- 2.约数
- 2.1试除法求约数
- 2.2约数个数
- 2.3约数之和
- 2.4最大公约数---欧几里得算法(辗转相除法)
1.质数
质数是针对所有大于1的自然数定义的,在大于1的整数中,如果只包含1和本身这两个约数,就被定义成为质数,或者叫素数。
1.1质数的判定—试除法
一个数的因数都是成对出现的:例如12的因数有3和4,2和6
所以我们可以只枚举较小的那一个,即根下n,假设较小的为d,较大的为n/d;
![在这里插入图片描述](https://img-blog.csdnimg.cn/4b2f4d43a9dd46258cf7fa64c4e6be47.png)
#include<iostream>
#include <algorithm>
using namespace std;
bool is_prime(int x)
{
if (x < 2) return false;
for (int i = 2; i <= x / i; i ++ )
if (x % i == 0)
return false;
return true;
}
int main()
{
int n;
cin >> n;
while (n -- )
{
int x;
cin >> x;
if (is_prime(x)) puts("Yes");
else puts("No");
}
return 0;
}
1.2分解质因数—试除法
质因数的定义:
![在这里插入图片描述](https://img-blog.csdnimg.cn/2f816c7d0bff4da394923d5e2587265b.png)
首先我们应该了解一下正常的教学做法:
![在这里插入图片描述](https://img-blog.csdnimg.cn/abe299d1d7714ea58a9023a5f8a062c4.png)
所以我们只需要进行这些步骤的模拟即可,也就是从2开始遍历循环不停的进行除法:
步骤详解
从2开始往后做除法,第一个能被除开的数一定是原数n的一个质数
for(int i=2;i<=n/i;i++)
if(n%i==0)
如果这个数是,那么继续对这个数轮番进行除法,且记录指数
int s=0;
while(n%i==0)
{
n/=i;
s++;
}
而如果除到最后n>1那么说明最后的这个n也是n的一个质数
为什么可以这样?
因为
n中最多只包含一个大于根号n的质因子
if(n>1)printf("%d %d\n",n,1);
代码实现:
- 若n是合数,那么它的最大的质因子不会超过sqrt(n)。
- 若n是质数,那么它只有一个质因子,且该质因子就是它本身,且大于sqrt(n)。
#include<bits/stdc++.h>
using namespace std;
void divide(int n){
for(int i=2;i<=n/i;i++){
if(n%i==0){
int s=0;
while(n%i==0) n/=i,s++;
cout<<i<<' '<<s<<endl;
}
}
if(n>1) cout<<n<<' '<<1<<endl;
cout<<endl;
}
int main(){
int n;
cin>>n;
for(int i=0;i<n;i++){
int a;
cin>>a;
divide(a);
}
}
1.3筛质数
(1)普氏筛法
思想:
i从2开始遍历到n,将i所有小于n的倍数全部划掉,剩下的便是质数。
特点:
好记
时间复杂度:
O
(
n
l
o
g
n
)
O( nlogn)
O(nlogn)
代码
void get_primes()
{
for (int i = 2; i <= n; i ++ )
{
if (!st[i]) primes[cnt ++ ] = i;
for (int j = 0; j <= n; j += i)
{
st[j] = true;
}
}
}
(2)埃氏筛法(埃及人发明的筛法)
思想:
其实跟普氏筛法差不多,只是只用质数去筛,因为合数筛掉的数肯定已经被比它小质数筛掉了,不需要再筛,所以只用质数筛即可。
特点:
思考简单
时间复杂度:
O
(
n
l
o
g
l
o
g
n
)
O(nloglogn)
O(nloglogn)
代码
void get_primes()
{
for (int i = 2; i <= n; i ++ )
{
if (!st[i])
{
primes[cnt ++ ] = i;
for (int j = i; j <= n; j += i)
{
st[j] = true;
}
}
}
}
(3) 线氏筛法
核心思想: 合数
x
x
x 只会被其最小质因子筛掉一次
为方便表述, 定义一个只有本文使用的术语:
“最小质因子左乘的方式” 表: 若
a
×
b
=
x
a×b=x
a×b=x, 则
a
a
a 表示
x
x
x 的最小质因子
算法过程
算法的主要逻辑是一个 for i = 2 to n
循环
循环的每一轮会做这样一个事情:
筛去以 “最小质因子左乘
i
i
i的方式” 得到的合数
x
x
x, 即:
筛去
a
×
i
=
x
a×i=x
a×i=x,
a
≤
i
a≤i
a≤i,
a
a
a为
x
x
x的最小质因子得到的合数
x
x
x
例:
![在这里插入图片描述](https://img-blog.csdnimg.cn/233d1d57e4df46f0b38dacc6dbd209f6.png)
注意:
3
×
4
3×4
3×4 并未在
i
=
4
i=4
i=4时被筛掉, 因为其会在
i
=
6
i=6
i=6时以 “最小质因子左乘的方式” 被
2
×
6
2×6
2×6 筛掉
![在这里插入图片描述](https://img-blog.csdnimg.cn/f8fd0a3429554cc6a25b57ec3f2518aa.png)
代码
int primes[N], cnt;
bool st[N];
void get_primes(int n)
{
for(int i = 2; i <= n; i++)
{
if(!st[i]) primes[cnt++] = i;
for(int j = 0; primes[j] <= n / i; j++)
{
st[primes[j] * i] = true;
if(i % primes[j] == 0) break;
}
}
}
2.约数
2.1试除法求约数
![在这里插入图片描述](https://img-blog.csdnimg.cn/0ffe3d969803477895d065a81d92fce9.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/f6b2c98e209e4767b662282801ed610d.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/94ddd5fb67ee426784194620d75ae53a.png)
代码:
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
int n;
void get_divisors(int 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);
}
}
}
sort(res.begin(), res.end());
for (auto item : res) {
cout << item << " ";
}
puts("");
}
int main()
{
cin >> n;
while (n--) {
int x;
cin >> x;
get_divisors(x);
}
return 0;
}
2.2约数个数
基于算数基本定理
![在这里插入图片描述](https://img-blog.csdnimg.cn/19c4f6109a7143099ca6587ba6b48fbf.png)
#include<iostream>
#include<algorithm>
#include<unordered_map>
using namespace std;
typedef long long LL;
const int mod = 1e9 + 7;
int main()
{
int n;
cin>>n;
unordered_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] ++;
}
LL res = 1;
for(auto prime : primes) res = res * (prime.second + 1) % mod;
cout<<res<<endl;
return 0;
}
2.3约数之和
![在这里插入图片描述](https://img-blog.csdnimg.cn/9fdf1e7a83994bd9ac95f0af0db098fc.png)
while (b -- ) t = (t * a + 1) % mod;
![在这里插入图片描述](https://img-blog.csdnimg.cn/53f1d9fc2f504cacb4d48310490a2038.png)
#include <iostream>
#include <algorithm>
#include <unordered_map>
#include <vector>
using namespace std;
typedef long long LL;
const int N = 110, mod = 1e9 + 7;
int main()
{
int n;
cin >> n;
unordered_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] ++ ;
}
LL res = 1;
for (auto p : primes)
{
LL a = p.first, b = p.second;
LL t = 1;
while (b -- ) t = (t * a + 1) % mod;
res = res * t % mod;
}
cout << res << endl;
return 0;
}
2.4最大公约数—欧几里得算法(辗转相除法)
解法一:直接用辗转相除法求解
![在这里插入图片描述](https://img-blog.csdnimg.cn/e8b191f7ba93412590efdc16b6401b87.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/f84433e6e8264378b78ca3e17460fb50.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/b23a48f1dfa84e4ca33aeec93a98f9b6.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/1198d5004b294aeab29f5a074ea650d0.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/018a3ea204bd4a27970317a0abc09a01.png)
#include<bits/stdc++.h>
using namespace std;
int n,a,b;
int gcd(int a, int b)
{
return b ? gcd(b, a % b) : a;
}
int main() {
cin >> n;
while(n--){
cin >> a >> b;
cout << gcd(a,b) << endl;
}
return 0;
}
解法2:使用STL中的__gcd函数
(注意!函数前面有两个下划线哦。即:是“__gcd
”而不是“_gcd
”)
库函数
#include<algorithm>
#include<bits/stdc++.h>
using namespace std;
int n,a,b;
int main() {
cin >> n;
while(n--){
cin >> a >> b;
cout << __gcd(a,b) << endl;
}
return 0;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)