1. 程式人生 > 其它 >線性代數(矩陣、高斯、線性基……)

線性代數(矩陣、高斯、線性基……)

一、主要內容

矩陣快速冪、高斯消元、線性基。


二、具體內容

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

線性基還可以推廣至非二進位制的情況。