「2020-2021 集训队作业」Yet Another Linear Algebra Problem(行列式,Binet-Cauchy 公式)

题面

出题人: T L Y \tt TLY TLY 太阳神:Tiw_Air_OAO


「 2020 — 2021   集 训 队 作 业 」 Y e t   A n o t h e r   L i n e a r   A l g e b r a   P r o b l e m 传 统       1000   m s       512   M i B {\tt「2020—2021~集训队作业」Yet~Another~Linear~Algebra~Problem}\\\\ {\tt_{传统~~~~~1000\,ms~~~~~512\,MiB}} 20202021 Yet Another Linear Algebra Problem     1000ms     512MiB

题目描述

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

问题一:给定 n n n 个在 G F ( 3 ) GF(3) GF(3)(数字都模 3 3 3)上的 m m m 维向量,记它们张成的线性空间为 V V V。求从 n n n 个向量中选出一组向量,使得它们是 V V V 的基的方案数。对 3 3 3 取模。

问题二:给定 n n n 个在 G F ( 2 ) GF(2) GF(2) 上的 m m m 维向量,记它们张成的线性空间为 V V V。其中第 i i i 个向量有颜色 c i c_i ci。求从每种颜色中恰好选出一个向量,使得它们是 V V V 的基的方案数。对 2 2 2 取模。

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

输入格式

第一行包含一个正整数 t a s k i d taskid taskid,表示需要解决的问题编号。

第二行包含两个正整数 n , m n,m n,m,含义见上。

接下来输入 n n n 行:

如果 t a s k i d = 1 taskid=1 taskid=1,则第 i i i 行包含 m m m 个非负整数 v i , 1 , v i , 2 , … , v i , m v_{i,1},v_{i,2},\ldots,v_{i,m} vi,1,vi,2,,vi,m,描述了第 i i i 个向量。

如果 t a s k i d = 2 taskid=2 taskid=2,则第 i i i 行包含 m + 1 m+1 m+1 个非负整数 v i , 1 , v i , 2 , … , v i , m , c i v_{i,1},v_{i,2},\ldots,v_{i,m},c_i vi,1,vi,2,,vi,m,ci,描述了第 i i i 个向量与它的颜色。

输出格式

输出一行一个正整数表示答案。

样例 1

输入

1
3 2
0 1
1 2
1 1

输出

0

样例 2

输入

1
4 3
1 1 0
1 2 0
1 2 2
1 1 1

输出

1

样例 3

输入

1
5 3
1 1 0
0 1 2
0 2 0
2 0 2
2 2 2

输出

2

样例 4

输入

2
3 2
0 1 1
0 0 2
1 1 1

输出

0

样例 5

输入

2
4 2
1 1 1
0 0 1
1 0 2
0 0 2

输出

1

数据范围与提示

对于 100 % 100\% 100% 的数据, t a s k i d ∈ { 1 , 2 } , 1 ≤ n , m ≤ 500 taskid\in\{1,2\},1\leq n,m\leq500 taskid{1,2},1n,m500

t a s k i d = 1 taskid=1 taskid=1 时,则 v i , j ∈ { 0 , 1 , 2 } v_{i,j}\in\{0,1,2\} vi,j{0,1,2}

t a s k i d = 2 taskid=2 taskid=2 时,则 v i , j ∈ { 0 , 1 } , c i ∈ [ 1 , m ] v_{i,j}\in\{0,1\},c_i\in[1,m] vi,j{0,1},ci[1,m]

s u b t a s k   1 ( 50   p t s ) : t a s k i d = 1 {\rm subtask~1(50~pts)}:taskid=1 subtask 1(50 pts):taskid=1

s u b t a s k   2 ( 50   p t s ) : t a s k i d = 2 {\rm subtask~2(50~pts)}:taskid=2 subtask 2(50 pts):taskid=2

L i b r e O J   P o w e r e d   b y   S Y Z O J   N G _{{\rm LibreOJ}~{\tt Powered~by}~{\rm SYZOJ~NG}} LibreOJ Powered by SYZOJ NG


题解

用到的知识很多。

首先,我们知道一个 n × n n\times n n×n 的矩阵是满秩的,等价于它的行列式非 0 0 0 ,那么选 m m m 个向量,是否能成为 V V V 的一组基底,就取决于它们拼成的 m × m m\times m m×m 矩阵是否行列式非 0 0 0


对于 s u b t a s k   1 \rm subtask~1 subtask 1 ,我们可以把答案表示为:
∑ 1 ≤ i 1 < i 2 < . . . < i m ≤ n [   ∣ — v i 1 → — — v i 2 → — ⋮ — v i m → — ∣ ≢ 0   ] m o d    3 \sum_{1\leq i_1<i_2<...<i_m\leq n} \left[~\left|\begin{matrix} —\overset{\rightarrow}{v_{i_1}}—\\ —\overset{\rightarrow}{v_{i_2}}—\\ \vdots\\ —\overset{\rightarrow}{v_{i_m}}—\\ \end{matrix}\right|\not\equiv0~\right]\mod 3 1i1<i2<...<imn vi1vi2vim0 mod3

中间那个条件符号不好处理啊!但是我们知道 1 2 , 2 2 1^2,2^2 12,22 在模 3 3 3 意义下都是等于 1 1 1 的,也就是说,把行列式平方,刚好同余于该条件表达式!那么我们就平方试试,顺便把其中一个行列式矩阵转置一下:
∑ 1 ≤ i 1 < i 2 < . . . < i m ≤ n ∣ ∣ ∣ ∣ ∣ v i 1 → v i 2 → … v i m → ∣ ∣ ∣ ∣ ∣ ⋅ ∣ — v i 1 → — — v i 2 → — ⋮ — v i m → — ∣ m o d    3 \sum_{1\leq i_1<i_2<...<i_m\leq n} \left|\begin{matrix} |&|&|&|\\ \overset{\rightarrow}{v_{i_1}}&\overset{\rightarrow}{v_{i_2}}&\dots&\overset{\rightarrow}{v_{i_m}}\\ |&|&|&|\\ \end{matrix}\right| \cdot \left|\begin{matrix} —\overset{\rightarrow}{v_{i_1}}—\\ —\overset{\rightarrow}{v_{i_2}}—\\ \vdots\\ —\overset{\rightarrow}{v_{i_m}}—\\ \end{matrix}\right| \mod 3 1i1<i2<...<imnvi1vi2vimvi1vi2vimmod3

再运用 B i n e t _ C a u c h y \tt Binet\_Cauchy Binet_Cauchy 公式,可以知道上式就等于
det ⁡ ( ( ∣ ∣ ∣ ∣ v 1 → v 2 → … v n → ∣ ∣ ∣ ∣ ) ⋅ ( — v 1 → — — v 2 → — ⋮ — v n → — ) ) \det\left(\left(\begin{matrix} |&|&|&|\\ \overset{\rightarrow}{v_{1}}&\overset{\rightarrow}{v_{2}}&\dots&\overset{\rightarrow}{v_{n}}\\ |&|&|&|\\ \end{matrix}\right) \cdot \left(\begin{matrix} —\overset{\rightarrow}{v_{1}}—\\ —\overset{\rightarrow}{v_{2}}—\\ \vdots\\ —\overset{\rightarrow}{v_{n}}—\\ \end{matrix}\right)\right) detv1v2vnv1v2vn

因此求这个行列式就行了。


对于 s u b t a s k   2 \rm subtask~2 subtask 2 ,在模 2 2 2 意义下,并没有变得更简单,而是多加了颜色条件。我们可以这样翻译这个条件:所选的 m m m 个向量的颜色必须互不相同,每种颜色都要有向量

这让我们又想到了一个关于行列式的性质:若行列式的某一行或某一列全为 0 0 0,那么行列式为 0 0 0

因此,我们可以用一个矩阵 A A A 表示颜色, A i , j A_{i,j} Ai,j 定义为向量 i i i 的颜色是( 1 1 1)否( 0 0 0)为 j j j 。每种颜色都要有向量,也就等价于 A A A 中对应的 m × m m\times m m×m 的子矩阵每行每列都有恰好一个 1 1 1 ,行列式不为 0 0 0

由于是取模 2 2 2 ,向量组成的行列式本身就等价于不等于 0 0 0 的条件表达式,可以不用平方。我们就把 A A A 的行列式乘过来表示答案:
∑ 1 ≤ i 1 < i 2 < . . . < i m ≤ n ∣ ∣ ∣ ∣ ∣ v i 1 → v i 2 → … v i m → ∣ ∣ ∣ ∣ ∣ ⋅ ∣ A i 1 , 1 A i 1 , 2 … A i 1 , m A i 2 , 1 A i 2 , 2 … A i 2 , m ⋮ ⋮ ⋱ ⋮ A i m , 1 A i m , 2 … A i m , m ∣ m o d    2 \sum_{1\leq i_1<i_2<...<i_m\leq n} \left|\begin{matrix} |&|&|&|\\ \overset{\rightarrow}{v_{i_1}}&\overset{\rightarrow}{v_{i_2}}&\dots&\overset{\rightarrow}{v_{i_m}}\\ |&|&|&|\\ \end{matrix}\right| \cdot \left|\begin{matrix} A_{i_1,1}&A_{i_1,2}&\dots&A_{i_1,m}\\ A_{i_2,1}&A_{i_2,2}&\dots&A_{i_2,m}\\ \vdots&\vdots&\ddots&\vdots\\ A_{i_m,1}&A_{i_m,2}&\dots&A_{i_m,m}\\ \end{matrix}\right| \mod 2 1i1<i2<...<imnvi1vi2vimAi1,1Ai2,1Aim,1Ai1,2Ai2,2Aim,2Ai1,mAi2,mAim,mmod2

又可以使用 B i n e t _ C a u c h y \tt Binet\_Cauchy Binet_Cauchy 公式了,把它变为
det ⁡ ( ( ∣ ∣ ∣ ∣ v 1 → v 2 → … v n → ∣ ∣ ∣ ∣ ) ⋅ A ) \det\left(\left(\begin{matrix} |&|&|&|\\ \overset{\rightarrow}{v_{1}}&\overset{\rightarrow}{v_{2}}&\dots&\overset{\rightarrow}{v_{n}}\\ |&|&|&|\\ \end{matrix}\right) \cdot A\right) detv1v2vnA

直接求行列式。

复杂度都是 O ( n 3 ) O(n^3) O(n3)

CODE

代 码 并 不 一 定 是 博 客 终 结 的 地 方 ^{_{代码并不一定是博客终结的地方}}

#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 505
#define ENDL putchar('\n')
#define LL long long
#define DB double
#define lowbit(x) ((-x) & (x))
LL read() {
	LL f = 1,x = 0;char s = getchar();
	while(s < '0' || s > '9') {if(s=='-')f = -f;s = getchar();}
	while(s >= '0' && s <= '9') {x=x*10+(s-'0');s = getchar();}
	return f * x;
}
int n,m,i,j,s,o,k;
int MOD = 1;
struct mat{
	int n,m;
	int s[500][500];
	mat(){n=m=0;memset(s,0,sizeof(s));}
	inline void set(int N,int M) {n=N;m=M;}
}X,A;
inline mat operator * (mat a,mat b) {
	mat c;c.set(a.n,b.m);
	for(int i = 0;i < a.n;i ++) {
		for(int k = 0;k < a.m;k ++) {
			if(a.s[i][k])
			for(int j = 0;j < b.m;j ++) {
				c.s[i][j] += a.s[i][k]*b.s[k][j];
			}
		}
	}
	for(int i = 0;i < c.n;i ++) {
		for(int j = 0;j < c.m;j ++) c.s[i][j] %= MOD;
	}return c;
}
mat T_mat(mat a) {
	for(int i = 0;i < a.n;i ++) {
		for(int j = i;j < a.m;j ++) {
			swap(a.s[i][j],a.s[j][i]);
		}
	}
	swap(a.n,a.m); return a;
}
int det(mat a) {
	if(a.n != a.m) return 0;
	int as = 1;
	for(int i = 0;i < a.n;i ++) {
		if(!(a.s[i][i]%MOD))
		for(int j = i;j < a.n;j ++) {
			if(a.s[j][i]%MOD) {swap(a.s[i],a.s[j]);as = MOD-as;break;}
		}
		if(!(a.s[i][i]%MOD)) return 0;
		for(int j = i+1;j < a.n;j ++) {
			if(a.s[j][i]%MOD) {
				for(int k = a.m-1;k >= i;k --) {
					(a.s[j][k] += MOD-a.s[i][k]*a.s[i][i]*a.s[j][i]%MOD) %= MOD;
				}
			}
		}
	}
	for(int i = 0;i < a.n;i ++) as = as * a.s[i][i] % MOD;
	return (as+MOD)%MOD;
}
int main() {
	int op = read();
	MOD = 4-op;
	n = read(); m = read();
	X.set(m,n);
	A.set(n,m);
	for(int i = 0;i < n;i ++) {
		for(int j = 0;j < m;j ++) {
			X.s[j][i] = read()%MOD;
		}
		if(op == 2) A.s[i][read()-1] = 1;
	}
	printf("%d\n",op == 1 ? det(X * T_mat(X)) : det(X * A));
	return 0;
}

后记

这道题好像是行列式和 B i n e t _ C a u c h y \tt Binet\_Cauchy Binet_Cauchy 公式的板题?

不论如何,给诸队爷出这种题, T L Y \tt TLY TLY 太阳神 也算仁慈了。

这个公式不是很常见,但是却又的确在 N O I \tt NOI NOI 大纲里。这样的知识也能掌握,祂必定是把行列式学透了的!不论学什么都深入学透,这就是我们和真正天才们的区别。

也是凡人和神的区别。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值