Pixiv - Miracle
4-抽象代数
2156 字
11 分钟
4-抽象代数
代数结构
| 结构 | 结构性质 | 逆运算 |
|---|---|---|
| ,Z | 阿贝尔群 | |
| ,Z | 阿贝尔群 | |
| ,R | 阿贝尔群 | - |
| ,R/{0} | 阿贝尔群 | / |
| & | 半格(无逆元的交换群) | |
| | | 半格(无逆元的交换群) | |
| max | 半格(无逆元的交换群) | |
| min | 半格(无逆元的交换群) | |
| ,所有矩阵,即矩阵加法 | 阿贝尔群 | - |
| ,所有矩阵,即矩阵乘法 | 幺半群 |
和同或有的关系
& 和 |和max和min
&
单位元:-1
性质
|
单位元:0
性质
max
单位元:LLONG_MAX
min
单位元:LLONG_MIN
高精度
高 + 高
// 高 + 高vector<int> add(vector<int> a, vector<int> b) { if (a.size() < b.size()) return add(b, a);
vector<int> c;
int t = 0; for (int i = 0; i < a.size(); ++i) { t += a[i]; if (i < b.size()) t += b[i]; c.emplace_back(t % 10); t /= 10; }
if (t) c.emplace_back(t); return c;}高 - 高
// 高 - 高vector<int> sub(vector<int> a, vector<int> b) { vector<int> c;
int t = 0; for (int i = 0; i < a.size(); ++i) { t += a[i]; if (i < b.size()) t -= b[i]; c.emplace_back((t + 10) % 10); if (t < 0) t = -1; }
while (c.size() > 1 && c.back() == 0) c.pop_back();
return c;}高 * 低
// 高 * 低vector<int> mul(vector<int> a, int b) { vector<int> c;
int t = 0; for (int i = 0; i < a.size() || t; ++i) { if (i < a.size()) t += a[i] * b; c.emplace_back(t % 10); t /= 10; }
while (c.size() > 1 && c.back() == 0) c.pop_back(); return c;}高 / 低
// 高 / 低vector<int> div(vector<int> a, int b) { vector<int> c;
int r = 0; for (int i = a.size() - 1; i >= 0; --i) { r = r * 10 + a[i]; c.emplace_back(r / b); r %= b; }
reverse(c.begin(), c.end()); while (c.size() > 1 && c.back() == 0) c.pop_back(); return c;}高 * 高
vector<int> mul(vector<int>& a, vector<int>& b) { vector<int> c(a.size() + b.size(), 0);
for (int i = 0; i < a.size(); ++i) { for (int j = 0; j < b.size(); ++j) { c[i + j] += a[i] * b[j]; } }
int t = 0; for (int i = 0; i < c.size(); ++i) { t += c[i]; c[i] = t % 10; t /= 10; }
while (c.size() > 1 && c.back() == 0) c.pop_back(); return c;}高 / 高
bool cmp(vector<int>& a, vector<int>& b) { if (a.size() != b.size()) return a.size() > b.size(); for (int i = a.size() - 1; i >= 0; --i) if (a[i] != b[i]) return a[i] > b[i]; return true;}
vector<int> div(vector<int>& a, vector<int>& b, vector<int>& r) { vector<int> c; r.clear();
for (int i = a.size() - 1; i >= 0; --i) { r.insert(r.begin(), a[i]);
while (r.size() > 1 && r.back() == 0) r.pop_back();
int x = 0; while (cmp(r, b)) { r = sub(r, b); x++; }
c.push_back(x); }
reverse(c.begin(), c.end()); while (c.size() > 1 && c.back() == 0) c.pop_back();
return c;}多项式
基础约定
// a[i] 表示 x^i 的系数(低位在前)using poly = vector<int>;
const int mod = 998244353;const int G = 3;加法
poly add(poly a, poly b) { if (a.size() < b.size()) swap(a, b); for (int i = 0; i < b.size(); ++i) a[i] = (a[i] + b[i]) % mod; return a;}减法
poly sub(poly a, poly b) { if (a.size() < b.size()) a.resize(b.size()); for (int i = 0; i < b.size(); ++i) a[i] = (a[i] - b[i] + mod) % mod;
while (a.size() > 1 && a.back() == 0) a.pop_back(); return a;}朴素乘法
poly mul(poly a, poly b) { poly c(a.size() + b.size() - 1);
for (int i = 0; i < a.size(); ++i) for (int j = 0; j < b.size(); ++j) c[i + j] = (c[i + j] + 1LL * a[i] * b[j]) % mod;
return c;}NTT乘除法
快速幂
int qpow(int a, int b) { int res = 1; while (b) { if (b & 1) res = 1LL * res * a % mod; a = 1LL * a * a % mod; b >>= 1; } return res;}
int inv(int x) { return qpow(x, mod - 2);}核心
void ntt(poly &a, bool invert) { int n = a.size(); static vector<int> rev; static vector<int> roots{0, 1};
if ((int)rev.size() != n) { int k = __builtin_ctz(n); rev.resize(n); for (int i = 0; i < n; ++i) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (k - 1)); }
if ((int)roots.size() < n) { int k = __builtin_ctz(roots.size()); roots.resize(n); while ((1 << k) < n) { int e = qpow(G, (mod - 1) >> (k + 1)); for (int i = 1 << (k - 1); i < (1 << k); ++i) { roots[2 * i] = roots[i]; roots[2 * i + 1] = 1LL * roots[i] * e % mod; } k++; } }
for (int i = 0; i < n; ++i) if (i < rev[i]) swap(a[i], a[rev[i]]);
for (int len = 1; len < n; len <<= 1) { for (int i = 0; i < n; i += 2 * len) { for (int j = 0; j < len; ++j) { int u = a[i + j]; int v = 1LL * a[i + j + len] * roots[len + j] % mod; a[i + j] = (u + v) % mod; a[i + j + len] = (u - v + mod) % mod; } } }
if (invert) { reverse(a.begin() + 1, a.end()); int inv_n = inv(n); for (int &x : a) x = 1LL * x * inv_n % mod; }}NTT乘法
poly mul_ntt(poly a, poly b) { int n = 1; while (n < a.size() + b.size()) n <<= 1;
a.resize(n); b.resize(n);
ntt(a, false); ntt(b, false);
for (int i = 0; i < n; ++i) a[i] = 1LL * a[i] * b[i] % mod;
ntt(a, true);
return a;}NTT带余除法
poly rev(poly a) { reverse(a.begin(), a.end()); return a;}
poly poly_div(poly a, poly b) { int n = a.size() - 1; int m = b.size() - 1;
if (n < m) return {0};
int k = n - m + 1;
poly ra = rev(a); poly rb = rev(b);
rb.resize(k);
poly inv_rb = poly_inv(rb, k);
poly rq = mul_ntt(ra, inv_rb); rq.resize(k);
poly q = rev(rq); return q;}
poly poly_mod(poly a, poly b) { poly q = poly_div(a, b); poly prod = mul_ntt(b, q);
poly r = sub(a, prod);
r.resize(b.size() - 1);
while (r.size() > 1 && r.back() == 0) r.pop_back(); return r;}
pair<poly, poly> poly_divmod(poly a, poly b) { poly q = poly_div(a, b); poly r = poly_mod(a, b); return {q, r};}乘法逆元
poly poly_inv(poly a, int n) { if (n == 1) return {inv(a[0])};
poly b = poly_inv(a, (n + 1) >> 1);
int size = 1; while (size < 2 * n) size <<= 1;
poly tmp = a; tmp.resize(size); b.resize(size);
ntt(tmp, false); ntt(b, false);
for (int i = 0; i < size; ++i) b[i] = 1LL * b[i] * (2 - 1LL * tmp[i] * b[i] % mod + mod) % mod;
ntt(b, true); b.resize(n);
return b;}导数
poly deriv(poly a) { if (a.size() == 1) return {0}; for (int i = 1; i < a.size(); ++i) a[i - 1] = 1LL * a[i] * i % mod; a.pop_back(); return a;}积分
poly integ(poly a) { a.push_back(0); for (int i = a.size() - 1; i > 0; --i) a[i] = 1LL * a[i - 1] * inv(i) % mod; a[0] = 0; return a;}多项式ln
poly poly_ln(poly a, int n) { poly da = deriv(a); poly inva = poly_inv(a, n);
poly res = mul_ntt(da, inva); res.resize(n - 1);
return integ(res);}多项式exp
poly poly_exp(poly a, int n) { if (n == 1) return {1};
poly b = poly_exp(a, (n + 1) >> 1);
poly ln_b = poly_ln(b, n);
poly diff = sub(a, ln_b); diff[0] = (diff[0] + 1) % mod;
b = mul_ntt(b, diff); b.resize(n);
return b;}多项式快速幂
poly poly_pow(poly a, int k, int n) { poly ln_a = poly_ln(a, n);
for (int &x : ln_a) x = 1LL * x * k % mod;
return poly_exp(ln_a, n);}线性基
普通
struct LinearBasis { static const int LOG = 60; // long long
long long d[LOG + 1]{};
// 插入一个数 void insert(long long x) { for (int i = LOG; i >= 0; --i) { if (!(x >> i & 1)) continue;
if (!d[i]) { d[i] = x; return; }
x ^= d[i]; } }
// 查询最大异或值 long long query_max() { long long res = 0; for (int i = LOG; i >= 0; --i) res = max(res, res ^ d[i]); return res; }};可求第k小
struct LinearBasis { static const int LOG = 60; long long d[LOG + 1]{}; vector<long long> p; // 重构后的基
void insert(long long x) { for (int i = LOG; i >= 0; --i) { if (!(x >> i & 1)) continue; if (!d[i]) { d[i] = x; return; } x ^= d[i]; } }
// 重构(变成上三角) void rebuild() { for (int i = 0; i <= LOG; ++i) for (int j = 0; j < i; ++j) if (d[i] >> j & 1) d[i] ^= d[j];
for (int i = 0; i <= LOG; ++i) if (d[i]) p.push_back(d[i]); }
// 第 k 小(0-based) long long kth(long long k) { if (k >= (1LL << p.size())) return -1;
long long res = 0; for (int i = 0; i < p.size(); ++i) if (k >> i & 1) res ^= p[i]; return res; }};高斯消元
浮点数
const int N = 110;const double eps = 1e-8;
double a[N][N]; // 增广矩阵 n 行 n+1 列
// 返回值:// 0 = 无解// 1 = 唯一解// 2 = 无穷多解int gauss(int n) { int r = 0, c = 0;
while (c < n) { // 1️ 找主元(绝对值最大) int t = r; for (int i = r; i < n; ++i) if (fabs(a[i][c]) > fabs(a[t][c])) t = i;
// 2️ 这一列全是0 → 自由变量 if (fabs(a[t][c]) < eps) { c++; continue; }
// 3️ 换行 for (int j = c; j <= n; ++j) swap(a[t][j], a[r][j]);
// 4️ 归一化 double div = a[r][c]; for (int j = c; j <= n; ++j) a[r][j] /= div;
// 5️ 消元(上下都消) for (int i = 0; i < n; ++i) { if (i != r && fabs(a[i][c]) > eps) { double factor = a[i][c]; for (int j = c; j <= n; ++j) a[i][j] -= factor * a[r][j]; } }
r++, c++; }
// 6️ 判断解的情况 for (int i = r; i < n; ++i) if (fabs(a[i][n]) > eps) return 0; // 无解
return r < n ? 2 : 1;}模2高斯消元
const int N = 110;
int a[N][N]; // n 行 n+1 列,值为 0/1
// 返回:0无解,1唯一解,2多解int gauss_xor(int n) { int r = 0;
for (int c = 0; c < n; ++c) { int t = r; for (int i = r; i < n; ++i) if (a[i][c]) { t = i; break; }
if (!a[t][c]) continue;
for (int j = c; j <= n; ++j) swap(a[t][j], a[r][j]);
for (int i = 0; i < n; ++i) if (i != r && a[i][c]) for (int j = c; j <= n; ++j) a[i][j] ^= a[r][j];
r++; }
for (int i = r; i < n; ++i) if (a[i][n]) return 0;
return r < n ? 2 : 1;}文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!
随机文章 随机推荐