[LOJ 3409] Yet Another Linear Algebra Problem

时间:2021-07-21
本文章向大家介绍[LOJ 3409] Yet Another Linear Algebra Problem,主要包括[LOJ 3409] Yet Another Linear Algebra Problem使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

一、题目

点此看题

二、解法

张成线性空间的维数是 \(m\) 等价于线性不相关的向量有 \(m\) 个,把向量写成 \(n\times m\) 的矩阵的秩是 \(m\)

这里普及一下比内\(-\)柯西公式,对于 \(s\times n\) 的矩阵 \(A\)\(n\times s\) 的矩阵 \(B\),若 \(s\leq n\),设矩阵 \(A_s\) 是任意取出 \(A\)\(s\) 列构成的 \(s\times s\) 的矩阵,\(B_s\) 是取出 \(B\) 中与 \(A_s\) 编号相对应的 \(s\) 行构成的 \(s\times s\) 的矩阵:

\[|AB|=\sum |A_s|\cdot |B_s| \]

对于子问题 \(1\),我们构造出 \(m\times n\) 的矩阵 \(A\) 为给定向量竖着排列的结果,答案是:

\[\sum |A_m|\cdot |A^T_m|=|AA^T| \]

因为如果选出来的 \(m\) 个向量不满秩的话,算出来的行列式是 \(0\);如果满秩算出来的行列式是 \(1/2\),因为把相同的向量构成矩阵的行列式乘了上去(只不过转置了一下),所以模 \(3\) 的结果一定是 \(1\),那么对总方案有 \(1\) 的贡献。

对于子问题 \(2\),我们再构造 \(n\times m\) 的矩阵 \(C\) 表示第 \(i\) 个向量是否有颜色 \(j\),答案是:

\[\sum |A_m|\cdot|C_m|=|AC| \]

因为首先要求选出来的 \(m\) 个向量满秩,前一个行列式就是 \(1\);再要求选出来的向量包含了所有颜色,也就是 \(C_m\) 满秩那么后一个行列式是 \(1\),当两个条件同时成立的时候产生 \(1\) 的贡献。

那么简单矩乘 \(+\) 高斯消元求行列式即可。

三、总结

主要是比内柯西公式的运用,这道题主要是选出的向量一定是 \(m\) 个,正好契合了此公式。

#include <cstdio>
#include <iostream>
using namespace std;
const int M = 505;
int read()
{
	int x=0,f=1;char c;
	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
int tp,n,m,a[M][M],b[M][M],c[M][M];
int gauss(int n,int p)
{
	int ans=1;
	for(int i=1;i<=n;i++)
	{
		for(int j=i;j<=n;j++)
			if(!c[i][i] && c[j][i])
			{
				ans=ans*(p-1)%p;
				swap(c[i],c[j]);
				break;
			}
		ans=ans*c[i][i]%p;
		for(int j=1;j<=n;j++)
		{
			if(i==j || !c[j][i]) continue;
			int t=c[j][i]*c[i][i]%p;
			for(int k=1;k<=n;k++)
				c[j][k]=(c[j][k]-t*c[i][k]%p+p)%p;
		}
	}
	return ans;
}
void work1()
{
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			a[j][i]=b[i][j]=read();
	for(int i=1;i<=m;i++)
		for(int j=1;j<=n;j++)
			for(int k=1;k<=m;k++)
				c[i][k]=(c[i][k]+a[i][j]*b[j][k])%3;
	printf("%d\n",gauss(m,3));
}
void work2()
{
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
			a[j][i]=read();
		b[i][read()]=1;
	}
	for(int i=1;i<=m;i++)
		for(int j=1;j<=n;j++)
			for(int k=1;k<=m;k++)
				c[i][k]=(c[i][k]+a[i][j]*b[j][k])%2;
	printf("%d\n",gauss(m,2));
}
signed main()
{
	tp=read();n=read();m=read();
	if(tp==1) work1(); 
	else work2();
}

原文地址:https://www.cnblogs.com/C202044zxy/p/15040393.html