boolis_prime(int x) { if (x < 2) returnfalse; for (int i = 2; i <= x / i; i ++ ) if (x % i == 0) returnfalse; returntrue; }
试除法分解质因数
思路:
x 的质因子最多只包含一个大于 根号 x 的质数。如果有两个,这两个因子的乘积就会大于 x,矛盾。
i 从 2 遍历到 根号 x。 用 x / i,如果余数为 0,则 i 是一个质因子。
s 表示质因子 i 的指数,x /= i 为 0,则 s++, x = x / i 。
最后检查是否有大于 根号 x 的质因子,如果有,输出。
1 2 3 4 5 6 7 8 9 10 11 12
voiddivide(int x) { for (int i = 2; i <= x / i; i ++ ) if (x % i == 0)//i 一定是质数 { int s = 0; while (x % i == 0) x /= i, s ++ ; cout << i << ' ' << s << endl; } if (x > 1) cout << x << ' ' << 1 << endl; cout << endl; }
int primes[N], cnt; // primes[]存储所有素数 bool st[N]; // st[x]存储x是否被筛掉
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] = true; } }
线性筛法求质数
核心思想:合数 x 只会被其最小质因子筛掉一次
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
int primes[N], cnt; // primes[]存储所有素数 bool st[N]; // st[x]存储x是否被筛掉
voidget_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; } } }
约数
试除法求约数
1 2 3 4 5 6 7 8 9 10 11 12
vector<int> get_divisors(int x) { vector<int> res; for (int i = 1; i <= x / i; i ++ ) if (x % i == 0) { res.push_back(i); if (i != x / i) res.push_back(x / i); } sort(res.begin(), res.end()); return res; }
usingnamespace std; typedeflonglong LL; constint N = 110, mod = 1e9 + 7; intmain() { 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) res = res * (p.second + 1) % mod; cout << res << endl; return0; }
usingnamespace std; typedeflonglong LL; constint N = 110, mod = 1e9 + 7; intmain() { 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;//遍历b次后得到t=p^b+p^(b-1)+...+p+1 res = res * t % mod; } cout << res << endl; return0; }
欧几里得算法求最大公约数
求最大公约数有多种 方法,常见的有 质因数分解法、 短除法、 辗转相除法、 更相减损法。
1 2 3 4
intgcd(int a, int b) { return b ? gcd(b, a % b) : a; }
最小公倍数
1 2 3 4
intlcm(int a, int b) { returnabs(a * b) / gcd(a, b); }
int primes[N], cnt; // primes[]存储所有素数 int euler[N]; // 存储每个数的欧拉函数 bool st[N]; // st[x]存储x是否被筛掉
voidget_eulers(int n)// 线性筛法求1~n的欧拉函数 { euler[1] = 1; for (int i = 2; i <= n; i ++ ) { if (!st[i]) { primes[cnt ++ ] = i; euler[i] = i - 1; } for (int j = 0; primes[j] <= n / i; j ++ ) { int t = primes[j] * i; st[t] = true; if (i % primes[j] == 0) { euler[t] = euler[i] * primes[j]; break; } euler[t] = euler[i] * (primes[j] - 1); } } }
快速幂
1 2 3 4 5 6 7 8 9 10 11 12 13
// 求 m^k mod p,时间复杂度 O(logk)。 // m为底数,k为幂 intqmi(int m, int k, int p) { int res = 1 % p, t = m; while (k) { if (k&1) res = res * t % p; t = t * t % p; k >>= 1; } return res; }
LL qmi(int a, int b, int p) { LL res = 1; while(b){ if(b & 1) res = res * a % p; a = (LL)a * a % p; b >>= 1; } return res; }
intmain() { int n; cin >> n; while(n --){ int a, p; cin >> a >> p; if(a % p == 0) puts("impossible"); else cout << qmi(a, p - 2, p) << endl; } return0; }
扩展欧几里得算法
1 2 3 4 5 6 7 8 9 10 11 12
// 求x, y,使得ax + by = gcd(a, b) intexgcd(int a, int b, int &x, int &y) { if (!b) { x = 1, y = 0; return a; } int d = exgcd(b, a % b, y, x); y -= (a/b) * x; return d; }
#include<iostream> usingnamespace std; typedeflonglong LL; int n;
intexgcd(int a, int b, int &x, int &y) { if (!b) { x = 1, y = 0; return a; } int d = exgcd(b, a % b, y, x); y -= a / b * x; return d; }
intmain() { cin >> n; while (n --) { int a, p, x, y; // if (a < p) swap(a, p); cin >> a >> p; int d = exgcd(a, p, x, y); if (d == 1) cout << ((LL)x + p) % p << endl;//保证x是正数 elseputs("impossible");
intgauss() { int c, r;// c 代表 列 col , r 代表 行 row for (c = 0, r = 0; c < n; c ++ ) { int t = r;// 先找到当前这一列,绝对值最大的一个数字所在的行号 for (int i = r; i < n; i ++ ) if (fabs(a[i][c]) > fabs(a[t][c])) t = i;
if (fabs(a[t][c]) < eps) continue;// 如果当前这一列的最大数都是 0 ,那么所有数都是 0,就没必要去算了,因为它的约束方程,可能在上面几行
for (int i = c; i < n + 1; i ++ ) swap(a[t][i], a[r][i]);//// 把当前这一行,换到最上面(不是第一行,是第 r 行)去 for (int i = n; i >= c; i -- ) a[r][i] /= a[r][c];// 把当前这一行的第一个数,变成 1, 方程两边同时除以 第一个数,必须要到着算,不然第一个数直接变1,系数就被篡改,后面的数字没法算 for (int i = r + 1; i < n; i ++ )// 把当前列下面的所有数,全部消成 0 if (fabs(a[i][c]) > eps)// 如果非0 再操作,已经是 0就没必要操作了 for (int j = n; j >= c; j -- )// 从后往前,当前行的每个数字,都减去对应列 * 行首非0的数字,这样就能保证第一个数字是 a[i][0] -= 1*a[i][0]; a[i][j] -= a[r][j] * a[i][c];
r ++ ;// 这一行的工作做完,换下一行 }
if (r < n)// 说明剩下方程的个数是小于 n 的,说明不是唯一解,判断是无解还是无穷多解 {// 因为已经是阶梯型,所以 r ~ n-1 的值应该都为 0 for (int i = r; i < n; i ++ )// if (fabs(a[i][n]) > eps)// a[i][n] 代表 b_i ,即 左边=0,右边=b_i,0 != b_i, 所以无解。 return2; return1;// 否则, 0 = 0,就是r ~ n-1的方程都是多余方程 } // 唯一解 ↓,从下往上回代,得到方程的解 for (int i = n - 1; i >= 0; i -- ) for (int j = i + 1; j < n; j ++ ) a[i][n] -= a[j][n] * a[i][j];//因为只要得到解,所以只用对 b_i 进行操作,中间的值,可以不用操作,因为不用输出
return0; }
intmain() { cin >> n; for (int i = 0; i < n; i ++ ) for (int j = 0; j < n + 1; j ++ ) cin >> a[i][j];
int t = gauss();
if (t == 0) { for (int i = 0; i < n; i ++ ) printf("%.2lf\n", a[i][n]); } elseif (t == 1) puts("Infinite group solutions"); elseputs("No solution"); return0; }
for(int i=0;i<cnt;++i) { // 当前的质数为 p int p=primes[i]; // 用分子里面 p 的个数减去分母里面 p 的个数。这里的计算组合数的公式为a!/(b!*(a-b)!),因此用 a 里面 p 的个数减去 b 里面 p 的个数和 (a-b) 里面 p 的个数。 sum[i]=get(a,p)-get(b,p)-get(a-b,p); }