一:筛质数:
1-埃氏筛法
该算法核心是从 2 开始,把每个质数的倍数标记为合数,时间复杂度约为 O(nloglogn)。
#include <iostream>
#include <vector>u
sing namespace std;
const int N = 1000010;
bool st[N]; // 标记数组,true表示是合数,false表示是质数
void get_primes(int n) {
for (int i = 2; i <= n; i++) {
if (!st[i]) {
for (int j = i + i; j <= n; j += i) {
st[j] = true;
}
}
}}
int main() {
int n;
cin >> n;
get_primes(n);
for (int i = 2; i <= n; i++) {
if (!st[i]) cout << i << ' ';
}
return 0;}
2-线性筛法:
在埃氏筛法的基础上进行进一步的优化,保证所有的合数都是被最小的质因子筛掉
#include <iostream>
#include <vector>
using namespace std;
const int N = 1000010;
int primes[N], cnt; // primes数组存储质数,cnt记录质数个数
bool st[N]; // 标记数组,true表示是合数,false表示是质数
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;
}
}
}
int main() {
int n;
cin >> n;
get_primes(n);
for (int i = 0; i < cnt; i++) {
cout << primes[i] << ' ';
}
return 0;
}
二:最大公约数和最小公倍数
最小公约数:
是扩展欧几里得的基础版本,可以求出a和b的最小公约数
int gcd(int a, int b) {
return b ? gcd(b, a % b) : a;
}
int main() {
int a, b;
cin >> a >> b;
cout << gcd(a, b) << endl;
return 0;
}
最小公倍数:
int lcm(int a, int b) {
return a*b/gcd(a, b);
}
三:质因数:分解质因数,质因数的和,质因数个数
分解质因数:
一个很暴力的做法,最后得到n的所有质因数
#include <iostream>
using namespace std;
void divide(int x) {
for (int i = 2; i <= x / i; i++) {
if (x % i == 0) {
int s = 0;
while (x % i == 0) {
x /= i;
s++;
}
cout << i << ' ' << s << endl;
}
}
if (x > 1) cout << x << ' ' << 1 << endl;
}
int main() {
int n;
cin >> n;
divide(n);
return 0;
}
约数的个数
若 N=p1^a1*p2^a2*⋯pk^ak,则 N 的约数个数为 (a1+1)(a2+1)⋯(ak+1)。
#include <iostream>
using namespace std;
int numofdividors(int x) {
int res=1;
for (int i = 2; i <= x / i; i++) {
if (x % i == 0) {
int s = 0;
while (x % i == 0) {
x /= i;
s++;
}
cout << i << ' ' << s << endl;
res=res*(s+1);
}
}
if (x > 1){
cout << x << ' ' << 1 << endl;
res*=2;
}
return res;
}
int main() {
int n;
cin >> n;
cout<<divide(n);
return 0;
}
约数的和
N=p1^a1*p2^a2⋯pk^ak则 N 的
约数和为 (p1^0+p1^1+⋯+p1^a1)(p2^0+p2^1+⋯+p2^a2)⋯(pk^0+pk^1++pk^ak)。
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;
}
四:快速幂和乘法逆元
快速幂可以在logn级别的时间里确定n^b mod p
#include <iostream>
using namespace std;
typedef long long LL;
快速幂:
LL qmi(int a, int k, int p) {
LL res = 1;
while (k) {
if (k & 1) res = res * a % p;
a = (LL)a * a % p;
k >>= 1;
}
return res;
}
int main() {
int a, k, p;
cin >> a >> k >> p;
cout << qmi(a, k, p) << endl;
return 0;
}
乘法逆元:
在mod p的环境下 a^-1 = a^ (p-2)
#include <iostream>
using namespace std;
typedef long long LL;
LL qmi(int a, int k, int p) {
LL res = 1;
while (k) {
if (k & 1) res = res * a % p;
a = (LL)a * a % p;
k >>= 1;
}
return res;
}
int main() {
int a, p;
cin >> a >> p;
if (a % p == 0) cout << "impossible" << endl;
else cout << qmi(a, p - 2, p) << endl;
return 0;
}
五:欧拉函数
欧拉函数 φ(n) 表示小于等于 n 且与 n 互质的正整数的个数。若 n=p1^a1*p2^a2*⋯pk^ak,
则 φ(n)=n(1−1/p1)(1−1/p2)⋯(1−1/pk)。
欧拉函数模版:
求出某一个数的欧拉函数值
#include <iostream>using namespace std;
int phi(int x) {
int res = x;
for (int i = 2; i <= x / i; i++) {
if (x % i == 0) {
res = res / i * (i - 1);
while (x % i == 0) x /= i;
}
}
if (x > 1) res = res / x * (x - 1);
return res;}
int main() {
int n;
cin >> n;
cout << phi(n) << endl;
return 0;
}
线性筛法求出1~n的欧拉函数:
只有一点点的改变
#include <iostream>
#include <vector>
using namespace std;
const int N = 1000010;
int primes[N], cnt; // primes数组存储质数,cnt记录质数个数
bool st[N]; // 标记数组,true表示是合数,false表示是质数
void get_primes(int n) {
for (int i = 2; i <= n; i++) {
if (!st[i]) {
primes[cnt++] = i;
phi[cnt-1]=i-1;
}
for (int j = 0; primes[j] <= n / i; j++) {
st[primes[j] * i] = true;
if (i % primes[j] == 0) {
phi[i*prime[j]]=phi[i]*prime[j];
break;
}
phi[i*prime[j]]=phi[i]*(prime[j]-1);
}
}
}
int main() {
int n;
cin >> n;
get_primes(n);
for (int i = 0; i < cnt; i++) {
cout << primes[i] << ' ';
}
return 0;
}