LOJ #3409. 「2020-2021 集训队作业」Yet Another Linear Algebra Problem 题解

Description

您需要解决两个独立(但类似)的子问题:

问题一:给定 nn 个在 GF(3)\mathrm{GF}(3) 上的 mm 维向量,记它们张成的线性空间为 VV。求从 nn 个向量中选出一组向量,使得它们是 VV 的基的方案数。对 33 取模。

问题二:给定 nn 个在 GF(2)\mathrm{GF}(2) 上的 mm 维向量,记它们张成的线性空间为 VV。其中第 ii 个向量有颜色 cic_i。求从每种颜色中恰好选出一个向量,使得它们是 VV 的基的方案数。对 22 取模。

注:为了凸显主要矛盾而忽略次要矛盾,保证 VV 的维数为 mm

1n,m5001\leq n,m\leq 500

Solution

首先有个前置知识是 Binet Cauchy 公式:

对于 m×nm\times n 的矩阵 AAn×mn\times m 的矩阵 BBnmn\geq m),有:(AS,BSA_S,B_S 表示列/行下标在 SS 中的子矩阵)

det(AB)=S=mdet(AS)det(BS)\det(AB)=\sum_{|S|=m}{\det(A_S)\det(B_S)}

第一问就是问有多少个大小为 mm 的子集,使得这个子集的秩非零。注意到在模 33 意义下,[x0]=x2[x\neq 0]=x^2,所以问题变为 S=mdet(AS)2=det(ATA)\displaystyle\sum_{|S|=m}{\det(A_S)^2}=\det(A^TA)

第二问等价于问 S=mdet(AS)[iS{ci}=U]\displaystyle\sum_{|S|=m}{\det(A_S)[\cup_{i\in S}{\{c_i\}}=U]},其中 uu 是颜色全集。考虑将第二个条件转为一个 n×mn\times m 的矩阵的行列式。

容易发现这等价于让 Bi,j=[j=ci]B_{i,j}=[j=c_i],如果 SS 中有元素颜色相同,则 BSB_S 的秩一定是 00,否则是 11。于是答案为 det(ATB)\det(A^TB)

时间复杂度:O(n3)O(n^3)

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#include <bits/stdc++.h>

// #define int int64_t

const int kMaxN = 505;

int taskid, n, m, mod;

struct Matrix {
int n, m, a[kMaxN][kMaxN];
void set(int _n, int _m) { n = _n, m = _m; }
friend Matrix operator *(Matrix &a, Matrix &b) {
static Matrix ret;
assert(a.m == b.n);
ret.set(a.n, b.m);
for (int i = 1; i <= a.n; ++i) {
for (int j = 1; j <= b.m; ++j) {
ret.a[i][j] = 0;
for (int k = 1; k <= a.m; ++k) ret.a[i][j] += a.a[i][k] * b.a[k][j];
ret.a[i][j] %= mod;
}
}
return ret;
}
} a, b;

int getdet(Matrix a) {
assert(a.n == a.m);
int n = a.n, ret = 1;
for (int i = 1; i <= n; ++i) {
if (!a.a[i][i]) {
for (int j = i + 1; j <= n; ++j) {
if (a.a[j][i]) {
std::swap(a.a[i], a.a[j]), ret = mod - ret;
break;
}
}
}
if (!a.a[i][i]) return 0;
ret = ret * a.a[i][i] % mod;
for (int j = i + 1; j <= n; ++j) {
int d = a.a[j][i] * a.a[i][i];
for (int k = i; k <= n; ++k) a.a[j][k] = (a.a[j][k] - a.a[i][k] * d + 3 * mod) % mod;
}
}
return (ret % mod + mod) % mod;
}

void dickdreamer() {
std::cin >> taskid >> n >> m;
if (taskid == 1) {
mod = 3, a.set(m, n), b.set(n, m);
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
std::cin >> b.a[i][j], a.a[j][i] = b.a[i][j];
std::cout << getdet(a * b) << '\n';
} else {
mod = 2, a.set(m, n), b.set(n, m);
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j)
std::cin >> a.a[j][i];
int c;
std::cin >> c;
b.a[i][c] = 1;
}
std::cout << getdet(a * b) << '\n';
}
}

int32_t main() {
#ifdef ORZXKR
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
std::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0);
int T = 1;
// std::cin >> T;
while (T--) dickdreamer();
// std::cerr << 1.0 * clock() / CLOCKS_PER_SEC << "s\n";
return 0;
}

LOJ #3409. 「2020-2021 集训队作业」Yet Another Linear Algebra Problem 题解
https://sobaliuziao.github.io/2025/08/27/post/e0a6b3a0.html
作者
Egg_laying_master
发布于
2025年8月27日
许可协议