基础线性代数
基础线性代数
矩阵变换
将向量逆时针旋转90°:左乘
0 -1
1 0
将向量延长至两倍:左乘
2 0
0 2
矩阵乘法
#include <bits/stdc++.h>
#define Mod 1000000007
#define maxn 3
using namespace std;
long long n,L=2;
struct Matrix{
long long M[maxn][maxn];
void clear(){ //矩阵清零
memset(M,0,sizeof(M));
}
void reset(){ //设置为单位矩阵
clear();
for(int i=0;i<L;++i) M[i][i]=1;
}
Matrix friend operator *(const Matrix &A,const Matrix &B){
Matrix Ans;
Ans.clear(); //L是矩阵的大小(行数与列数)
for(int i=0;i<L;++i){
for(int j=0;j<L;++j){
for(int k=0;k<L;++k){
Ans.M[i][j]=(Ans.M[i][j]+A.M[i][k]*B.M[k][j])%Mod;
}
}
}
return Ans;
}
}A,B,C;
int main(){
for(int i=0;i<L;i++){
for(int j=0;j<L;j++){
cin>>A.M[i][j];
}
}
for(int i=0;i<L;i++){
for(int j=0;j<L;j++){
cin>>B.M[i][j];
}
}
//可以这么计算矩阵乘法,其中A、B、C均为Matrix类型
C=A*B;
for(int i=0;i<L;i++){
for(int j=0;j<L;j++){
cout<<C.M[i][j]<<" ";
}
cout<<endl;
}
return 0;
}
矩阵快速幂
例题:洛谷P1962 斐波那契数列
P1962 斐波那契数列 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
求出Fn mod 109+7的值
n<=2,Fn=1
n>2,Fn=Fn-2+Fn-1
我们可以想到,通过矩阵加速递推
F(n-1) -> F(n)
F(n-2) F(n-1)
所以我们可以推出
F(n) = 1 1 * F(n-1)
F(n-1) 1 0 F(n-2)
所以
F(n) = 1 1 ^(n-2) * 1
F(n-1) 1 0 1
用矩阵快速幂求出
1 1 ^(n-2)
1 0
然后求出Fn=[0][0]+[0][1]
#include <bits/stdc++.h>
#define Mod 1000000007
#define maxn 3
using namespace std;
long long n,L=2;
struct Matrix{
long long M[maxn][maxn];
void clear(){ //矩阵清零
memset(M,0,sizeof(M));
}
void reset(){ //设置为单位矩阵
clear();
for(int i=0;i<L;++i) M[i][i]=1;
}
Matrix friend operator *(const Matrix &A,const Matrix &B){
Matrix Ans;
Ans.clear(); //L是矩阵的大小(行数与列数)
for(int i=0;i<L;++i){
for(int j=0;j<L;++j){
for(int k=0;k<L;++k){
Ans.M[i][j]=(Ans.M[i][j]+A.M[i][k]*B.M[k][j])%Mod;
}
}
}
return Ans;
}
}A;
Matrix expow(Matrix T,long long P){ //矩阵快速幂
Matrix Ans;
Ans.reset();
while(P){
if(P&1) Ans=Ans*T;
T=T*T,P>>=1;
}
return Ans;
}
int main(){
cin>>n;
if(n<=2){
cout<<1;
return 0;
}
A.M[0][0]=1;
A.M[0][1]=1; //构造递推矩阵
A.M[1][0]=1;
A.M[1][1]=0;
A=expow(A,n-2); //矩阵快速幂
cout<<(A.M[0][0]+A.M[0][1])%Mod; //计算结果
return 0;
}
另一类似题 P1939 【模板】矩阵加速(数列)
P1939 【模板】矩阵加速(数列) - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
易得,递推矩阵为
0 1 0
0 0 1
1 0 1
高斯消元
例题 P2455 线性方程组
[P2455 SDOI2006]线性方程组 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
n为未知数个数,接下来n行 输入每一行的系数和b值
如果有唯一解,则输出解(小数点后保留两位小数)。如果方程组无解输出 -1; 如果有无穷多实数解,输出 0;
\[a_{11}x_1+a_{12}x_2+...+a_{1n}x_n=b_1\\
a_{21}x_1+a_{22}x_2+...+a_{2n}x_n=b_2\\
...\\
a_{n1}x_1+a_{n2}x_2+...+a_{nn}x_n=b_n
\]
#include <bits/stdc++.h>
using namespace std;
#define maxn 110
#define eps 1e-6
int n,curi=0; //curi表示枚举哪一行
double a[maxn][maxn];
int main(){
cin>>n;
for(int i=0;i<n;i++)
for(int j=0;j<n+1;j++)
cin>>a[i][j];
for(int j=0;j<n;j++){
int t;
for(t=curi;t<n;t++)
if(fabs(a[t][j])>eps) break; //找到一列非零元素
if(t==n) continue; //这一列没有找到非零元素
for(int i=j;i<=n;i++)
swap(a[t][i],a[curi][i]); //把非0元素所在行交换到当前行
for(int i=n;i>=j;i--)
a[curi][i] /= a[curi][j]; //当前行同除,令主元系数划一
for(int i=0;i<n;i++) //对其他行消元
if(i!=curi)
for(int k=n;k>=j;k--)
a[i][k]-=a[curi][k]*a[i][j];
curi++;
}
if(curi<n){ //判断0!=0
for(int i=curi;i<n;i++)
if(fabs(a[i][n])>eps){ //发现0!=0,无解
puts("-1");
return 0;
}
puts("0"); //发现0=0,无穷多解
}else
for(int i=0;i<n;i++)
printf("x%d=%.2lf\n",i+1,a[i][n]);
return 0;
}
行列式求值
例题 P7112 行列式求值
P7112 【模板】行列式求值 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
输入n和p(模数),接下来输入这个行列式
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
const int maxn=602;
int a[maxn][maxn];
int n,p,i,j;
int cal(int a[][maxn],int n,int p)
{
int i,j,k,r=1,fh=0,l;
for (i=1;i<=n;i++)
{
k=i;
for(j=i;j<=n;j++){
if(a[j][i]){
k=j;
break;
}
}
if(a[k][i]==0) return 0;
for(++j;j<=n;j++){
if(a[j][i]&&a[j][i]<a[k][i]) k=j;
}
if(i!=k){
swap(a[k],a[i]);
fh^=1;
}
for(j=i+1;j<=n;j++)
{
if(a[j][i]>a[i][i]){
swap(a[j],a[i]);
fh^=1;
}
while(a[j][i])
{
l=a[i][i]/a[j][i];
for(k=i;k<=n;k++)
a[i][k]=(a[i][k]+(ll)(p-l)*a[j][k])%p;
swap(a[j],a[i]);
fh^=1;
}
}
r=(ll)r*a[i][i]%p;
}
if(fh) return (p-r)%p;
return r;
}
int main()
{
IOS;
cin>>n>>p;
for(i=1;i<=n;i++){
for(j=1;j<=n;j++){
cin>>a[i][j];
a[i][j]%=p;
}
}
cout<<cal(a,n,p);
}