//有 d | n //显然(n / d) | d 也成立 //所以所有枚举的数只需要满足d <= n / d 就可以了 //不推荐使用d <= sqrt(n),因为每次执行的时候都会调用一次sqrt函数 //也不推荐使用d * d <= n,因为当n接近于INT_MAX时存在溢出风险
boolis_prime(int n) { if (n < 2) return0; for (int i = 2; i <= n / i; i++) { if (n % i == 0) return0; } return1; }
分解质因数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
//n中最多只包含一个大于sqrt(n)的质因子 //使用反证法,如果包含两个a, b那么存在a * b > n这与已知矛盾
voiddivide(int N) { int n = N; for (int i = 2; i <= N / i; i++) { if (n % i == 0) { int sum = 0; while (n % i == 0) { n /= i; sum++; } cout << i << " " << sum << endl; } } if (n > 1) cout << n << " " << 1 << endl; }
#include<bits/stdc++.h> #define int long long usingnamespace std;
voidsolve() { int n, k; // 我们要找到 <= k的最大的 n 的除数 cin >> n >> k; int ans = n; for (int i = 1; i <= n / i; i++) { if (n % i== 0) { // a * b <= n if (i <= k) { ans = min(ans, n / i); } if (n / i <= k) { ans = min(ans, i); } } } cout << ans << endl; }
signedmain() { ios::sync_with_stdio(0);cin.tie(0);cout.tie(0); int t = 1; cin >> t; while(t--){ solve(); } return0; }
埃氏筛法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
constint N = 1000010; int primes[N], cnt; bool st[N];
voidget_primes(int n){ for (int i = 2; i <= n; i++) { //如果被筛选过了,那么就跳过此次循环 if (st[i]) continue; //记录素数 primes[cnt++] = i; //筛选倍数 for (int j = i + i; j <= n; j += i) { st[j] = 1; } } }
线性筛法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
constint N = 1000010; int primes[N], cnt; bool st[N];
voidget_primes(int n){ //这种方法的实质就是就是筛选每个数的最小质因子 //所以每个合数都会被筛选到,并且只会被筛选一次 for (int i = 2; i <= n; i++) { //如果这里还没被筛选,那么这里的数就是质数 if (!st[i]) primes[cnt++] = i; //这里的写法可以看作primes[j] * i <= n //也就是在i确定的时候可以选取哪几个素数 for (int j = 0; primes[j] * i <= n; j++) { st[primes[j] * i] = 1; //遍历到最小质因数的时候退出循环 if (i % primes[j] == 0) break; } } }
约数
试除法求约数
1 2 3 4 5 6 7 8 9 10 11 12
vector<int> get_divisors(int n) { vector<int> ans; for (int i = 1; i <= n / i; i++) { if (n % i == 0) { ans.push_back(i); if (i != n / i) ans.push_back(n / i); } } sort(ans.begin(), ans.end()); return ans; }
voiddivide(int N) { int n = N; for (int i = 2; i <= N / i; i++) { if (n % i == 0) { while (n % i == 0) { n /= i; cnt[i]++; } } } if (n > 1) cnt[n]++; }
voidsolve() { int n; cin >> n; vector<int> arr(n); for (int i = 0; i < n; i++) { cin >> arr[i]; divide(arr[i]); } int sum = 1; for (auto x : cnt) { sum *= (x.second + 1); sum %= mod; } cout << sum << endl; }
voiddivide(int N) { int n = N; for (int i = 2; i <= N / i; i++) { if (n % i == 0) { while (n % i == 0) { n /= i; cnt[i]++; } } } if (n > 1) cnt[n]++; }
voidsolve() { int n; cin >> n; vector<int> arr(n); for (int i = 0; i < n; i++) { cin >> arr[i]; divide(arr[i]); } int ans = 1; for (auto x : cnt) { int temp = 1; while (x.second--) { temp = (temp * x.first + 1) % mod; } ans = ans * temp % mod; } cout << ans << endl; }
//性质1 //d | a , d | b --> d | x * a + y * b //证明: //d | a --> d * k1 = a; //d | b --> d * k2 = b; //x * a + y * b = x * d * k1 + y * d * k2 //d | x * a + y * b
//辗转相除法原理 //(a, b) = (b, a % b);
//a % b = a - a / b * b; //c = a / b //等价与证明(a, b) = (a, a - c * b) //由性质1,这是显然的
intgcd(int a, int b) { //b不是0返回gcd(b, a % b) //b是0返回a return b ? gcd(b, a % b) : a; }
// 证明 // 1,从1 ~ N中去掉所有p1, p2, ... pk的倍数 // N - N / p1 - N / p2 - ... - N / pk // 有可能有些数会重复去除 // 2,加上所有pi * pj 的倍数 // 3,减去所有pi * pj * pk的倍数 // . // . // . // 把这个式子合并就能得到结论 intphi(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);
// 证明 // 在 1 ~ n 中与 n 互质的数不妨设为 // a1, a2, a3, ... , aphi[n] // 不妨构造一个数列 // a * a1, a * a2, a * a3, ... , a * aphi[n] // 因为 a 与 n 互质,a1, a2, a3, ... , aphi[n] 也与 n 互质,所以乘积也和 n 互质 // 假设存在a * ai ≡ a * aj (mod n) (i != j) // a 和 n 互质,所以可以同时消掉 a // 得到 ai ≡ aj,这是不可能的,与假设矛盾 // 所以这个式子两两不同 // 把这个数列每个式子 mod n 就可以与原数列一一映射 // a1 * a2 ... aphi[n] ≡ a ^ phi[n] * a1 * a2 ... aphi[n] (mod n) // a ^ phi[n] ≡ 1 (mod n)