【线性代数】

线代前置知识:3B1B的视频和课本
代码大量参考佳叔。

矩阵

矩阵快速幂板子。
UVA 10870 Recurrences
矩阵表示线性递推关系。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int sz = 17;
int n,d;
int MOD;
struct mat{
    ll a[sz][sz];
    inline mat() {memset(a,0,sizeof(a));}
    inline mat operator-(const mat& T) const{
        mat res;
        for(int i=0;i<d;++i)
            for(int j=0;j<d;++j)
                res.a[i][j]=(a[i][j]-T.a[i][j]+MOD)%MOD;
        return res;
    }
    inline mat operator+(const mat& T) const{
        mat res;
        for(int i=0;i<d;++i)
            for(int j=0;j<d;++j)
                res.a[i][j]=(a[i][j]+T.a[i][j])%MOD;
        return res;
    }
    inline mat operator*(const mat& T) const{
        mat res;
        int r;
        for(int i=0;i<d;++i)
            for(int k=0;k<d;++k){
                r=a[i][k];
                for(int j=0;j<d;++j)
                    res.a[i][j]+=T.a[k][j]*r,res.a[i][j]%=MOD;
            }
        return res;
    }
    inline mat operator^(ll x) const{
        mat res,bas;
        for(int i=0;i<d;++i) res.a[i][i]=1;
        for(int i=0;i<d;++i)
            for(int j=0;j<d;++j) bas.a[i][j]=a[i][j]%MOD;
        while(x){
            if(x&1) res=res*bas;
            bas=bas*bas;
            x>>=1;
        }
        return res;
    }
};

int main(){
    while(~scanf("%d%d%d",&d,&n,&MOD),(d||n||MOD)){
        mat a;
        for(int i=0;i<d;++i){
            int tmp;scanf("%d",&tmp);
            a.a[0][i]=tmp;
        }
        for(int i=1;i<d;++i) a.a[i][i-1]=1;
        mat x;
        for(int i=d-1;i>=0;--i) {
            int tmp;scanf("%d",&tmp);
            x.a[i][0]=tmp;
        }
        if(n<=d){
            cout<<x.a[n-1][0]<<endl;
            continue;
        }
        a=a^(n-1);
        x=a*x;
        cout<<x.a[d-1][0]<<endl;
    }
}

UVA 1386 Cellular Automaton
细胞自动机。
数据范围不允许O(n^3log n)。发现转移矩阵是个circulant matrix。
两个循环矩阵乘积还是循环矩阵。
只保存一行。O(n^2log n)。最后 A x A x Ax的时候也是用保存的那一行,推出全部,跟x以O(n^2)相乘。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,m,d,k;
const int N = 504;

struct mat{
    ll v[N];
    mat() {memset(v,0,sizeof(v));}
    inline mat operator *(mat c) const{
        mat ans;
        for(int i=0;i<n;++i)
            for(int j=0;j<n;++j)
                ans.v[i]=(ans.v[i]+v[j]*c.v[(i-j+n)%n])%m;
        return ans;
    }
};

mat qpow(mat x,ll k){
    if(k==1) return x;
    mat tmp=x*x;
    mat res=qpow(tmp,k>>1);
    if(k&1) res=res*x;
    return res;
}

int b[N];

int main(){
    while(~scanf("%lld%lld%lld%lld",&n,&m,&d,&k)){
        mat a;
        for(int i=0;i<=d;++i) a.v[i]=1;
        for(int i=n-1;i>=n-d;--i) a.v[i]=1;
        a=qpow(a,k);
        for(int i=0;i<n;++i) scanf("%lld",&b[i]);
        for(int i=0;i<n;++i){
            ll ans=0;
            for(int j=0;j<n;++j)
                ans=(ans+b[j]*a.v[(j-i+n)%n])%m;
            printf("%lld%c",ans,(i==n-1?'\n':' '));
        }
    }
}

UVA 10828 Back to Kernighan-Ritchie
随机程序。
给一张概率自动机图,1号点是起点。要求每个结点的期望执行次数。
lrj思路:每个节点的答案由其pre节点得出,可列多条方程。
解多元一次方程组,用高斯约当消元法
注意观察什么时候得出infinite,什么时候0.
结合高斯约当的特质来看。
RREF的特质就是:可逆情况下,adjacency matrix的对角线才有数字。当出现矛盾方程,会有前面为0,后面不为0的情况。当出现多余方程,会出现全为0的情况。
下图这种情况(*)也可能出现。此时,我们发现第3条方程是矛盾方程,那么 x 3 x_3 x3就是infinity(在此题目语意下)。那么,与他有关的第一条方程的解 x 1 x_1 x1也是infinity。
在这里插入图片描述

在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
int n;
const int N = 110;
const double eps = 1e-8;
int out[N];  // 用来算概率
vector<int> pre[N];  // 前驱

typedef double Matrix[N][N];

Matrix matrix;

void gauss_jordan(Matrix A,int n){
    int i,j,k,r;
    for(i=0;i<n;++i){
        r=i;
        for(j=i+1;j<n;++j)
            if(fabs(A[j][i])>fabs(A[r][i])) r=j;
        if(fabs(A[r][i])<eps) continue;//i是自由变量
        if(r!=i) for(j=0;j<=n;++j) swap(A[i][j],A[r][j]);
        // 变成对角矩阵
        for(k=0;k<n;++k) if(k!=i)
            for(j=n;j>=i;--j)
                A[k][j]-=A[k][i]/A[i][i]*A[i][j];
    }
}

int inf[N];  // check if is inf
int main(){
    int cas=0;
    while(~scanf("%d",&n),n){
        int u,v;
        for(int i=0;i<n;++i) pre[i].clear();
        memset(out,0,sizeof(out));
        while(~scanf("%d%d",&u,&v),(u||v)){
            u--,v--;
            pre[v].push_back(u);
            out[u]++;
        }
        memset(matrix,0,sizeof(matrix));
        for(int i=0;i<n;++i){
            matrix[i][i]=1;
            for(int j=0;j<pre[i].size();++j)
                matrix[i][pre[i][j]]-=1.0/out[pre[i][j]];
            if(i==0) matrix[i][n]=1;
        }
        gauss_jordan(matrix,n);
        memset(inf,0,sizeof(inf));
        for(int i=n-1;i>=0;--i){
            if(fabs(matrix[i][i])<eps&&fabs(matrix[i][n])>eps) inf[i]=1;
            for(int j=i+1;j<n;++j)
                if(fabs(matrix[i][j])>eps&&inf[j]) inf[i]=1;
                // 处理(*)的情况
        }
        int q;scanf("%d",&q);
        cout<<"Case #"<<++cas<<":"<<endl;
        while(q--){
            scanf("%d",&u);u--;
            if(inf[u]) cout<<"infinity"<<endl;
            else printf("%.3lf\n",fabs(matrix[u][u])<eps?0.0:matrix[u][n]/matrix[u][u]);
        }
    }
}

洛谷[SDOI2010]外星千足虫
异或方程组裸题,问是否有自由变量,有的话输出cannot determine,无就输出用了前多少个方程求出了所有解,并输出解。
玄学的时间复杂度,居然过了(。

#include<bits/stdc++.h>
using namespace std;
char ss[1002];
int A[2002][1002];

void result(int m,int n){
    int i=0,j=0,k,r,u;
    int las=0;
    while(i<m&&j<n){
        r = i;
        for(k=i;k<m;++k)
            if(A[k][j]) {r = k;break;}
        if(A[r][j]){
            las = max(las,r);
            if(r!=i) for(k=0;k<=n;++k) swap(A[r][k],A[i][k]);
            for(u=i+1;u<m;++u) if(A[u][j])
                for(k=i;k<=n;++k) A[u][k] ^= A[i][k];
            i++;
        }
        j++;
    }
    if(i<n){
        cout<<"Cannot Determine"<<endl;return;
    }// free variable
    cout<<las+1<<endl;
    for(i=n-1;i>=0;i--)
        for(j=i-1;j>=0;j--)
        if(A[j][i]) A[j][n] ^= A[i][n];
    for(i=0;i<n;++i) {
        if(A[i][n]) cout<<"?y7M#"<<endl;
        else cout<<"Earth"<<endl;
    }
}

int main() {
    int n,m;cin>>n>>m;
    int res;
    for(int i=0;i<m;++i){
        // m 条方程, n 个变量
        scanf("%s",ss);
        scanf("%d",&res);
        for(int j=0;j<n;++j) {
            A[i][j] = ss[j] - '0';
        }
        A[i][n] = res;
    }
    result(m,n);
}

线性基

一篇讲得很好的博文

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值