线性代数(矩阵、高斯、线性基……)

时间:2021-07-25
本文章向大家介绍线性代数(矩阵、高斯、线性基……),主要包括线性代数(矩阵、高斯、线性基……)使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

一、主要内容

矩阵快速幂、高斯消元、线性基。


二、具体内容

\(1.\) 矩阵

矩阵加法:

相同位置相加。

矩阵乘法:

满足分配率、结合律,不满足交换律(矩阵与逆矩阵之间除外)

矩阵转置:

记矩阵为 \(A\) ,则 \(A\) 的转置记为 \(A^T\)

性质:

  • \[{(A^T)}^T=A \]
  • \[{(A+B)}^T=A^T+B^T \]
  • \[{(k\times A)}^T=k\times A^T \]
  • \[{(AB)}^T=A^TB^T \]

矩阵求逆:

P4783 【模板】矩阵求逆

对左半边的矩阵做高斯消元,同时更新右半边的部分,(交换时也一起交换,但最终不用再换回来了)。而做完之后的右半边部分就是求得的逆矩阵。

\(2.\) 高斯消元

复杂度(朴素): \(O(n^3)\)

主要代码:

scanf("%d",&n);
for(int i=1;i<=n;i++) for(int j=1;j<=n+1;j++) scanf("%lf",&a[i][j]);
for(int i=1,Max=1;i<=n;Max=++i)
{
	 for(int s=i+1;s<=n;s++) if(fabs(a[s][i])>fabs(a[Max][i])) Max=s; // 找出绝对值最大的 
	 for(int j=1;j<=n+1;j++) swap(a[i][j],a[Max][j]);
	 if(a[i][i]<10e-8 && a[i][i]>-10e-8) { p=false; break; } // 记得 double 的精度问题 
	 for(int s=1;s<=n;s++) if(s!=i) // 这样省去了第二步处理的麻烦 
	 {
	 	 double tmp=0-(a[s][i]/a[i][i]);
	 	 a[s][i]=0;
	 	 for(int j=i+1;j<=n+1;j++) a[s][j]+=tmp*a[i][j];
	 }
}
if(p) for(int i=1;i<=n;i++) printf("%.2lf\n",a[i][n+1]/a[i][i]);
else printf("No Solution\n");

\(3.\) 线性基

线性基为一个数集构造出来的新数集,满足以下性质:

  • 线性基的元素能相互异或得到原集合的元素的所有相互异或得到的值

  • 线性基是满足性质 \(1\)最小的集合

  • 线性基没有异或和为 \(0\) 的子集。

  • 线性基中不同的异或组合异或出的数都是不一样的。

  • 线性基中每个元素的二进制最高位互不相同

用处:

  • 快速查询一个数是否可以被一堆数异或出来

  • 快速查询一堆数可以异或出来的最大 \(/\) 最小值

  • 快速查询一堆数可以异或出来的第 \(k\) 大值

\(1.\) 处理线性基

void Insert(ll x)
{
	 for(int i=62;i>=0;i--)
	 {
	 	 if(!(x & (1ll<<(ll)i))) continue; // 防止对高位影响 
	 	 if(!p[i]) { p[i]=x; break; }
	 	 x^=p[i]; // 更新 [0,i-1] 位的更优答案 
	 }
	 if(!x) zero=1ll; // 特判 0 
}

\(2.\) 查询一个元素是否可以被异或出来

bool ask(ll x)
{
	 for(int i=62;i>=0;i--) if(x&(1ll<<(ll)i)) x^=p[i];
	 return x==0;
}

$3. $ 查询异或最大值

ll query_max()
{
	 ll ret=0;
	 for(int i=62;i>=0;i--) if((ans^p[i])>ans) ans^=p[i];
	 return ans;
}

\(4.\) 查询异或最小值

ll query_min()
{
	 for(int i=0;i<=62;i++) if(p[i]) return p[i];
	 return 0;
}

\(5.\) 查询异或第 \(k\)

void rebuild()
{
	 // 重建 d 数组,求出哪些位可以被异或为 1
	 // d[i] 只有第 i 个二进制位为 1 
	 for(int i=62;i>=1;i--) // 从高到低防止后效性 
	 	 for(int j=i-1;j>=0;j--)
	 	 	 if(p[i] & (1ll<<(ll)j)) p[i]^=p[j];
	 for(int i=0;i<=62;i++) if(p[i]) d[cnt++]=p[i];
}
ll kth(ll k)
{
	 if(!k) return 0ll; // 特判 0 
	 if(k>=(1ll<<(ll)cnt)) return -1ll; // k 大于可以表示出的数的个数 
	 ll ret=0;
	 for(int i=62;i>=0;i--) if(k & (1ll<<(ll)i)) ret^=d[i];
	 return ret;
}

线性基还可以推广至非二进制的情况。

原文地址:https://www.cnblogs.com/EricQian/p/15057448.html