线性代数学习

这周学习了线性代数,感觉很厉害的样子。。。

高斯消元

对于一组多项式方程(增广矩阵中,x[i, n+1]表示式子的值;x[i,j]表示第i个方程第j项的系数,在这里,增广矩阵可能不一定是n个,可能多可能少;opt表示运算规则):
(x[1,1]*a[1]) opt (x[1,2]*a[2]) opt … opt (x[1,n]*a[n])=x[1, n+1]
(x[2,1]*a[1]) opt (x[2,2]*a[2]) opt … opt (x[2,n]*a[n])=x[2, n+1]

(x[n,1]*a[1]) opt (x[n,2]*a[2]) opt … opt (x[n,n]*a[n])=x[n, n+1]
常见的opt有+和异或
消元:我们对于每个方程,假设为i,且x[i][now]不为0(now是当前被消元的变元,更一般的,只要能支持消掉后边方程的系数即可),然后对所有的j>i的方程,我们将所有x[j][now]不为0(或者需要消元的)用一种方式消掉。

回代:最后我们得到的是一个x[i][i]均不为0的方程(除非无解或此方程无意义)的倒三角矩阵。然后根据性质3将当前方程的其它j>i的a[j]和系数根据性质3转移到右式消去即可(此时a[j]一定是求出来的)

无解的情况:当存在一个矩阵使得左式=0而右式!=0那么无解。
自由变元:自由变元就是当这些未知量一旦确定,整个方程就确定了。但是这些量是未知的。(例如x+y=5,自由变元就是1,因为无论是x还是y确定,另一个就能唯一确定),而答案要求的是方案,那么显然因为自由变元是可以随便赋值的,而如果这些值只有2个,开和不开,那么方案数就是2^自由变元。
仅当n个不同的方程(就是无论怎么通过其它方程都不会将这两个方程变成一样)才能确定n个解。那么我们如果只确定了x个方程,那么自由变元的数量就是n-x。(这个x可以轻易得到,因为在高斯消元过程中,会将所有不同的方程消元,因为消元会将相同的方程消成这个样子:0=0。所以就能得到x了。
复杂度O(n^3)
代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
#define f(i,a,b) for(int i=a;i<=b;i++)
const double eps=0.000000001;
const int N=101;
double a[N][N+1];
int n;
int main(){
  cin>>n;
  f(i,1,n){
      f(j,1,n+1) cin>>a[i][j];
  }
  f(i,1,n){
      int top=i;
      f(j,i,n) if(fabs(a[j][i]-a[top][i])<=eps) top=j;
      f(j,1,n+1) swap(a[i][j],a[top][j]);
      if(fabs(a[i][i])<=eps){
          cout<<"No Solution"<<endl;
          return 0;
      }
      f(j,i+1,n+1) a[i][j]/=a[i][i];
      f(j,1,n)
        if(i!=j)
          f(k,i+1,n+1) a[j][k]-=a[j][i]*a[i][k];
  }
  f(i,1,n) printf("%.2lf\n",a[i][n+1]);
  return 0;
}

矩阵快速幂

同正常快速幂

矩阵加速线性递推

例如求斐波那契数列,可以构造矩阵然后矩阵的幂就是答案

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;

struct Matrix {
    long long a[4][4];
}ans;

int mod = 1e9 + 7;;

Matrix Matrix_mul(Matrix A, Matrix B) {
    Matrix C;
    memset(C.a, 0 , sizeof(C.a));
    for(int i = 1; i <= 3; ++i)
        for(int j = 1; j <= 3; ++j)
            for(int k = 1; k <= 3; ++k)
                C.a[i][j] = (C.a[i][j] + A.a[i][k] * B.a[k][j] % mod) % mod;
    return C;
}

Matrix qpow(Matrix A, int n) {
    if(n <= 1) return A;
    Matrix B = A; --n;
    while(n) {
        if(n & 1) B = Matrix_mul(B, A);
        n >>= 1;
        A = Matrix_mul(A, A);
    }
    return B;
}

int main() {
    memset(ans.a, 0, sizeof(ans.a));
    ans.a[1][1] = 1; ans.a[1][2] = 1; ans.a[1][3] = 0;
    ans.a[2][1] = 0; ans.a[2][2] = 0; ans.a[2][3] = 1;
    ans.a[3][1] = 1; ans.a[3][2] = 0; ans.a[3][3] = 0;
    int T, x;
    cin >> T;
    while(T--) {
        cin >> x;
        Matrix A;
        memset(A.a, 0, sizeof(A.a));
        A = qpow(ans, x - 1);
        cout << A.a[1][1] << endl;
    }
    return 0;
}

线性基

xor运算神器

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<cstring>
#include<queue>
#include<cmath>
#include<map>
#include<set>
using namespace std;
#define REP(i, a, b) for(int i = a; i <= b; i++)
#define PER(i, a, b) for(int i = a; i >= b; i--)
#define LL long long
inline LL read(){
    LL x = 0, flag = 1;char ch = getchar();
    while(!isdigit(ch)) {
        if(ch == '-') flag = - 1;
        ch = getchar();
    }
    while(isdigit(ch)) x = x * 10 + ch - '0', ch = getchar();
    return x * flag;
}

template<typename T> struct linear_base {
    static const int maxlog = 60; 
    T a[61];
    void ins(T x) {
        for(T i = maxlog; i >= 0; --i) {
            if(x & ((T)(1) << i)) {
                if(!a[i]) {
                    a[i] = x;
                    return;
                } else x ^= a[i];
            }
        }
    }

    bool check(T x) {
        for(T i = maxlog; i >= 0; --i) 
            if(x & ((T)(1) << i)) {
                if(!a[i]) return 0;
                else x ^=a[i];
            }
        return 1;
    }

    T qmax() {
        T res = 0;
        for(T i = maxlog; i >= 0; --i)
            if((res ^ a[i]) > res) res ^= a[i];
        return res;
    }

    T qmin() {
        for(T i = 0; i <= maxlog; ++i)
            if(a[i]) return a[i];
    }

    T query(int k) {
        T tmp[61], res = 0, cnt = 0;
        for(T i = 0; i <= maxlog; ++i) {
            for(int j = i - 1; j >= 0; --j)
                if(a[i] & ((T)(1) << j))
                    a[i] ^= a[j];
            if(a[i]) tmp[cnt++] = a[i];
        }
        for(T i = 0; i < cnt; ++i)
            if(k & ((T)(1) << i)) res ^= tmp[i];

        return res;
    }
};

linear_base<LL> s;

int main() {   
    int n = read();
    REP(i, 1, n) s.ins(read());
    printf("%lld\n", s.qmax());
	return 0;
}

经典例题

给出一些运用矩阵运用线性代数的典型例题

UVa10870

Consider recurrent functions of the following form:
f(n) = a1f(n − 1) + a2f(n − 2) + a3f(n − 3) + . . . + adf(n − d), for n > d,
where a1, a2, . . . , ad are arbitrary constants.
A famous example is the Fibonacci sequence, defined as: f(1) = 1, f(2) = 1, f(n) = f(n − 1) +
f(n − 2). Here d = 2, a1 = 1, a2 = 1.
Every such function is completely described by specifying d (which is called the order of recurrence),
values of d coefficients: a1, a2, . . . , ad, and values of f(1), f(2), . . . , f(d). You’ll be given these numbers,
and two integers n and m. Your program’s job is to compute f(n) modulo m.

矩阵加速线性递推,构造相伴矩阵 F n = A ∗ F n − 1 F_n = A * F_{n-1} Fn=AFn1 A 为对角线为1最后一行为a的矩阵, F ( n ) = A n − d ∗ F ( d ) F(n)=A^{n-d}*F(d) F(n)=AndF(d)

#include<iostream>
#include<string>
#include<cstring>
using namespace std;

const int maxn = 20;
typedef long long Matrix[maxn][maxn];
typedef long long Vector[maxn];

int sz, mod;
void matrix_mul(Matrix A, Matrix B, Matrix res) {
  Matrix C;
  memset(C, 0, sizeof(C));
  for(int i = 0; i < sz; i++)
    for(int j = 0; j < sz; j++)
      for(int k = 0; k < sz; k++) C[i][j] = (C[i][j] + A[i][k] * B[k][j]) % mod;
  memcpy(res, C, sizeof(C));
}

void matrix_pow(Matrix A, int n, Matrix res) {
  Matrix a, r;
  memcpy(a, A, sizeof(a));
  memset(r, 0, sizeof(r));
  for(int i = 0; i < sz; i++) r[i][i] = 1;
  while(n) {
    if(n&1) matrix_mul(r, a, r);
    n >>= 1;
    matrix_mul(a, a, a);
  }
  memcpy(res, r, sizeof(r));
}

void transform(Vector d, Matrix A, Vector res) {
  Vector r;
  memset(r, 0, sizeof(r));
  for(int i = 0; i < sz; i++)
    for(int j = 0; j < sz; j++)
      r[j] = (r[j] + d[i] * A[i][j]) % mod;
  memcpy(res, r, sizeof(r));
}

int main() {
  int d, n, m;
  while(cin >> d >> n >> m && d) {
    Matrix A;
    Vector a, f;

    for(int i = 0; i < d; i++) { cin >> a[i]; a[i] %= m; }
    for(int i = d-1; i >= 0; i--) { cin >> f[i]; f[i] %= m; }

    memset(A, 0, sizeof(A));
    for(int i = 0; i < d; i++) A[i][0] = a[i];
    for(int i = 1; i < d; i++) A[i-1][i] = 1;

    sz = d;
    mod = m;
    matrix_pow(A, n-d, A);
    transform(f, A, f);

    cout << f[0] << endl;
  }
  return 0;
}

UVa1386

有一个细胞自动机,它是一个由 n 个元素组成的环,每个元素的值都必须是 \pmod {m}(modm) 意义下的。现在你需要对这个环进行 k 次操作,每次操作你需要把这个环内每个元素更新成与它距离不超过 d 的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值