目录
(2)线性筛--->>时间复杂度为O(N)(所以一般情况下都使用这个)
数论的一些模板:
这是我之前写的一些模板:详细的步骤过程在里面,这里只是核心步骤
根据蓝桥杯重点考察的回顾一下重点的数论算法
(1)朴素筛法求素数
核心:
内循环遍历完质因子的倍数,并将其标记为合数
#include<iostream>
using namespace std;
const int N = 1000010;
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 = i + i; j <= n; j += i) st[j] = 1;//间隔
}
}
}
int main()
{
int n;
cin >> n;
get_primes(n);
cout << cnt;
}
(2)线性筛--->>时间复杂度为O(N)(所以一般情况下都使用这个)
核心:
思路与上面的朴素筛法差不多,都是标记倍数,不过线性筛每次时标记离自己最近那个倍数
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1000010;
int primes[N], cnt;
bool st[N];
void get_primes(int n)//12
{
for (int i = 2; i <= n; i++)
{
if (!st[i])//如果没有被标记过:证明时素数
{
primes[cnt++] = i;//primes[0]=2 primes[1]=3
}
for (int j = 0; primes[j] <= n / i; j++)
{//st[4]=1 st[6]=1 st[9]=1
st[primes[j] * i] = 1;//遍历素数数组,标记素数的i倍为true
if (i % primes[j] == 0) break;//2%2==0 3%3==0 意思时遍历到最后primes数组的最后一个数了 break
}
}
}
int main()
{
int n;
cin >> n;
get_primes(n);
cout << cnt;
return 0;
}
(3)分解数字为质因数
核心:
公理:每个数字都可被拆分为质因数^指数的乘积形式(如下图所示)
#include<iostream>
using namespace std;
void divide(int n)
{
for (int i = 2; i <= n / i; i++)
{
if (n % i == 0)
{//i一定是质数,因为此时2到i-1的质因子已经被除干净了
int s = 0;//计算次数
while (n % i == 0)
{
n /= i;//i为什么是质数的原因
s++;
}
printf("%d %d\n", i, s);
}
}
if (n > 1) printf("%d %d\n", n, 1);//特判:当有一个比较大的质因子时
cout << endl;
}
int main()
{
int n;
cin >> n;
while (n--)
{
int x;
cin >> x;
divide(x);
}
return 0;
}
(4)约数的个数
核心:如下图
#include<iostream>
#include<unordered_map>
using namespace std;
const int mod = 1e9 + 7;
typedef long long ll;
int main()
{
int n;
cin >> n;
ll ans = 1;//因为要连乘,所以初始化为1
unordered_map<int, int> hash;
while (n--)
{
int x;
cin >> x;
for (int i = 2; i <= x / i; i++)
{
while (x % i == 0)
{
x /= i;//分解质因数
hash[i]++;//质因数的指数++(次数即指数)
}
}
if (x > 1) hash[x]++;//保留最后一个质因数
}
for (auto &i : hash) ans = ans * (i.second + 1) % mod;//约数公式
cout << ans;
return 0;
}
(5)约数之和
核心:如下图
#include <iostream>
#include <algorithm>
#include <unordered_map>
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; // while (b -- ) t = (t * a + 1) % mod; 是什么意思?
res = res * t % mod;
}
cout << res << endl;
return 0;
}
(6)欧几里得算法(辗转相除)
核心:
gcd(a,b)=gcd(b,a%b)
(1)当b==0时,0与任意一个数的最大公约数都是它本身
(2)当b!=0时就是gcd(a,b)=gcd(b,a%b)
#include<iostream>
#include<algorithm>
usin