4-抽象代数

2156 字
11 分钟
4-抽象代数

代数结构#

结构结构性质逆运算
\oplus,Z阿贝尔群\oplus
\odot,Z阿贝尔群\odot
++,R阿贝尔群-
×\times,R/{0}阿贝尔群/
&半格(无逆元的交换群)\varnothing
|半格(无逆元的交换群)\varnothing
max半格(无逆元的交换群)\varnothing
min半格(无逆元的交换群)\varnothing
++,所有矩阵,即矩阵加法阿贝尔群-
×\times,所有矩阵,即矩阵乘法幺半群\varnothing

\oplus#

和同或有ab=ab1a \odot b = a \oplus b \oplus 1的关系

& 和 |和max和min#

ab=a+ba&b==0a | b = a + b\leftrightarrow a \& b == 0

&

单位元:-1

性质

  1. 0a & bmin(a,b)当且仅当a=b时取等,全存在0时最小0 \le a\space \& \space b \le min(a,b)\text{当且仅当}a=b\text{时取等,全存在}0\text{时最小}

|#

单位元:0

性质

  1. max(a,b)a  ba+b当且仅当ab相加无进位时取等max(a,b) \le a\space | \space b \le a + b\text{当且仅当}a\text{和}b\text{相加无进位时取等}

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;
}

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

4-抽象代数
https://skaco2.com/posts/01-algorithm/4-抽象代数/
作者
SKACO2
发布于
2026-04-08
许可协议
CC BY-NC-SA 4.0

评论区

Profile Image of the Author
SKACO2
Hello……
公告
欢迎来到我的博客!
音乐
封面

音乐

暂未播放

0:00 0:00
暂无歌词
分类
标签
站点统计
文章
53
分类
8
标签
54
总字数
58,255
运行时长
0
最后活动
0 天前

目录