PART 1 素数筛
埃氏筛
逆用试除法 —— 用素数排除合数
没什么好说的
//埃氏筛
void Eratosthenes() {
vis[0] = vis[1] = false; //提前处理好1与0 合数标记为false,素数标记为true
for (int i = 2; i <= sqrt(n); i++) {
if (vis[i] == true) { // i 为 素数
for (int j = i * i; j <= n; j += i) { //标记i^2 ~ n 中所有素数i的倍数
vis[j] = false;
}
}
}
}
例题:找质数2、【竞速赛Round3】How many primes?等
应用场景较广,适用大部分题。
时间复杂度:O(nlogn)
Tips: 注意题目N的范围, 若多组样例,思考是否预处理。
欧拉筛(线性筛)
每次筛掉部分素数倍数,而非一次性筛完所有倍数
有说的但我不是很会
void ols() {
int cnt = 0;
for (int i = 2; i <= n; i++) {
if (vis[i] == true) prime[++cnt] = i;
for (int j = 1; j <= cnt && i * prime[j] <= n; j++) { // 避免超出范围
prime[i * prime[j]] = false; //只筛除一部分
if (i % prime[j] == 0) break;
}
}
}
速度较快,适用几乎所有题
时间复杂度:O(n)
PART 2 同余方程
//同余方程
int exgcd (int a, int b, int &x, int &y) {
if (b == 0) {
x = 1;
y = 0;
return a;
} else {
int d = exgcd (b, a % b, y, x); //辗转相除
y -= a / b * x;
return d;
}
}
题目通常为数学问题,会直接点出“同余”
PART 3 欧拉函数
通式:fai(x) = x * ( 1 - 1 / p1) * (1 - 1 / p2)……* (1 - 1 / pn)
p1,p2,p3……pn为x的所有质因数
法1:基于素因数分解求欧拉函数
int euler (int x) { //基于整数分解定理
int ans = x;
int a = x;
for (int i = 2; i <= sqrt(a); i++) {
if (a % i == 0) ans -= ans / i;
while (a % i == 0) a /= i; //除尽质因子i
}
if (a > 1) ans -= ans / a; //防止a为质数
return ans;
}
• 时间复杂度为O(sqrt(n))
Tips:只能求出一个数
法2:埃氏筛(打表)
void euler(int n) {
for (int i = 1; i <= n; i++) phi[i] = i;
for (int i = 2; i <= n; i++) {
if (phi[i] == i) {
for (int j = i; j <= n; j += i) {
phi[j] = phi[j] / i * (i - 1);
}
}
}
}
可以求出1~n中所有的fai(i)
补充:快慢乘
//快慢乘
int quick (int a, int b, int mod) {
int ans = 0;
while (b) {
if (b & 1) ans = (ans + a) % mod;
a = (a << 1) % mod;
b >>= 1;
}
return ans;
}
int slow (int a, int b, int mod) {
int ans = 0;
while (b > 0) {
if (b & 1) ans = (ans + a) % mod;
b >>= 1;
a = (a + a) % mod;
}
return ans;
}
int mod (int a, int b, int mod) {
int sum = 1;
while (b > 0) {
if (b & 1) sum = slow(sum, a, mod);
a = slow(a, a, mod);
b >>= 1;
}
return sum;
}
644

被折叠的 条评论
为什么被折叠?



