zoukankan      html  css  js  c++  java
  • 矩阵乘法题集

    矩阵 A×B

    模板题。

    感觉写完结构体就可以为所欲为了。

    #include<bits/stdc++.h>
    #define REP(i, a, b) for(register int i = (a); i < (b); i++)
    #define _for(i, a, b) for(register int i = (a); i <= (b); i++)
    using namespace std;
    
    typedef long long ll;
    const int MAXN = 100 + 10;
    struct Matrix
    {
    	int n, m;
    	ll c[MAXN][MAXN];
    	
    	Matrix() { memset(c, 0, sizeof(c)); }
    	
    	void read()
    	{
    		_for(i, 1, n)
    			_for(j, 1, m)
    				scanf("%lld", &c[i][j]);
    	}
    	
    	Matrix operator * (const Matrix& a)
    	{
    		Matrix r;
    		r.n = n; r.m = a.m;
    		_for(i, 1, r.n)
    			_for(j, 1, r.m)
    				_for(k, 1, m)
    					r.c[i][j] += c[i][k] * a.c[k][j];
    		return r;
    	}
    	
    	void print()
    	{
    		_for(i, 1, n)
    		{
    			_for(j, 1, m)
    				printf("%lld ", c[i][j]);
    			puts("");
    		}
    	}
    }A, B, C;
    
    int main()
    {
    	scanf("%d%d", &A.n, &A.m); B.n = A.m;
    	A.read();
    	scanf("%d", &B.m);
    	B.read();
    	C = A * B;
    	C.print();
    	return 0;
    }

    Fibonacci 第 n 项

    大概总结一下构造矩阵的方法

    fn = fn-1 + fn-2

    我们可以构造一个1x2的矩阵

    使得

    [fn-2, fn-1] * A = [fn-1, fn] = [fn-1, fn-1+fn-2]

    A是一个2*2的矩阵

    可以求得A是

    0 1
    1 1

    矩阵快速幂即可

    #include<bits/stdc++.h>
    #define REP(i, a, b) for(register int i = (a); i < (b); i++)
    #define _for(i, a, b) for(register int i = (a); i <= (b); i++)
    using namespace std;
    
    typedef long long ll;
    const int MAXN = 100 + 10;
    int MOD, k;
    
    struct Matrix
    {
    	int n, m;
    	ll c[MAXN][MAXN];
    	
    	Matrix() { memset(c, 0, sizeof(c)); }
    	
    	Matrix operator * (const Matrix& a)
    	{
    		Matrix r;
    		r.n = n; r.m = a.m;
    		_for(i, 1, r.n)
    			_for(j, 1, r.m)
    				_for(k, 1, m)
    					r.c[i][j] = (r.c[i][j] + c[i][k] * a.c[k][j] % MOD) % MOD;
    		return r;
    	}
    };
    
    Matrix power(Matrix a, int b)
    {
    	Matrix res; res.n = res.m = 2;
    	_for(i, 1, res.n) res.c[i][i] = 1;
    	for(; b; b >>= 1)
    	{
    		if(b & 1) res = res * a;
    		a = a * a;
    	}
    	return res;
    }
    
    int main()
    {
    	scanf("%d%d", &k, &MOD);
    	Matrix A; A.n = A.m = 2;
    	A.c[1][2] = A.c[2][1] = A.c[2][2] = 1;
    	A = power(A, k - 1);
    	
    	Matrix ans; ans.n = 1; ans.m = 2;
    	ans.c[1][1] = ans.c[1][2] = 1;
    	ans = ans * A;
    	printf("%lld
    ", ans.c[1][1]);
    	
    	return 0;
    }

    Fibonacci 前 n 项和

    在矩阵中加入一个sn进去就好了。

    构造矩阵记得往后推以及分解

    #include<bits/stdc++.h>
    #define REP(i, a, b) for(register int i = (a); i < (b); i++)
    #define _for(i, a, b) for(register int i = (a); i <= (b); i++)
    using namespace std;
    
    typedef long long ll;
    const int MAXN = 100 + 10;
    int MOD, k;
    
    struct Matrix
    {
    	int n, m;
    	ll c[MAXN][MAXN];
    	
    	Matrix() { memset(c, 0, sizeof(c)); }
    	
    	Matrix operator * (const Matrix& a)
    	{
    		Matrix r;
    		r.n = n; r.m = a.m;
    		_for(i, 1, r.n)
    			_for(j, 1, r.m)
    				_for(k, 1, m)
    					r.c[i][j] = (r.c[i][j] + c[i][k] * a.c[k][j] % MOD) % MOD;
    		return r;
    	}
    };
    
    Matrix power(Matrix a, int b)
    {
    	Matrix res; res.n = res.m = 3;
    	_for(i, 1, res.n) res.c[i][i] = 1;
    	for(; b; b >>= 1)
    	{
    		if(b & 1) res = res * a;
    		a = a * a;
    	}
    	return res;
    }
    
    int main()
    {
    	scanf("%d%d", &k, &MOD);
    	Matrix A; A.n = A.m = 3;
    	A.c[1][1] = A.c[2][1] = A.c[3][1] = 1;
    	A.c[3][2] = A.c[3][3] = A.c[2][3] = 1;
    	A = power(A, k - 2);
    	
    	Matrix ans; ans.n = 1; ans.m = 3;
    	ans.c[1][1] = 2;
    	ans.c[1][2] = ans.c[1][3] = 1;
    	ans = ans * A;
    	printf("%lld
    ", ans.c[1][1]);
    	
    	return 0;
    }

    佳佳的 Fibonacci

    这道题推的真的太爽了!!

    看到有n*fn

    那么我们就再矩阵中加入n*fn

    所以就是

    [Tn-1, (n-2)Fn-2, (n-1)Fn-1,Fn-1,Fn-2]

    推到

    [Tn, (n-1)Fn-1, nFn,Fn,Fn-1]

    所以可以构造出A

    1 0 0 0 0

    1 0 1 0 0

    1 1 1 0 0

    1 0 1 1 1

    2 0 2 1 0

    初始矩阵为[3,1,2,1,1]

    #include<bits/stdc++.h>
    #define REP(i, a, b) for(register int i = (a); i < (b); i++)
    #define _for(i, a, b) for(register int i = (a); i <= (b); i++)
    using namespace std;
    
    typedef long long ll;
    const int MAXN = 100 + 10;
    int MOD, k;
    
    struct Matrix
    {
    	int n, m;
    	ll c[MAXN][MAXN];
    	
    	Matrix() { memset(c, 0, sizeof(c)); }
    	
    	Matrix operator * (const Matrix& a)
    	{
    		Matrix r;
    		r.n = n; r.m = a.m;
    		_for(i, 1, r.n)
    			_for(j, 1, r.m)
    				_for(k, 1, m)
    					r.c[i][j] = (r.c[i][j] + c[i][k] * a.c[k][j] % MOD) % MOD;
    		return r;
    	}
    };
    
    Matrix power(Matrix a, int b)
    {
    	Matrix res; res.n = res.m = 5;
    	_for(i, 1, res.n) res.c[i][i] = 1;
    	for(; b; b >>= 1)
    	{
    		if(b & 1) res = res * a;
    		a = a * a;
    	}
    	return res;
    }
    
    int main()
    {
    	scanf("%d%d", &k, &MOD);
    	if(k == 1) { puts("1"); return 0; }
    	Matrix A; A.n = A.m = 5;
    	A.c[1][1] = 1;
    	A.c[2][1] = A.c[2][3] = 1;
    	A.c[3][1] = A.c[3][2] = A.c[3][3] = 1;
    	A.c[4][1] = A.c[4][3] = A.c[4][4] = A.c[4][5] = 1;
    	A.c[5][1] = A.c[5][3] = 2; A.c[5][4] = 1;
    	A = power(A, k - 2);
    	
    	Matrix ans; ans.n = 1; ans.m = 5;
    	ans.c[1][1] = 3;
    	ans.c[1][2] = ans.c[1][4] = ans.c[1][5] = 1;
    	ans.c[1][3] = 2;
    	ans = ans * A;
    	printf("%lld
    ", ans.c[1][1]);
    	
    	return 0;
    }

    bzoj 1009

    这道题写了好久!!!

    这道题用到了三个知识点,kmp,dp,矩阵乘法。

    设f[i][j]为前i个字符的后缀匹配到不吉利串的前j个字符的方案数(第一次见到这样的状态设计)

    那么转移方程为f[i][next(j)] = sum(f[i-1][j])

    从j到next(j)可以用kmp算法求出来

    然后这个转移可以用矩阵快速幂来优化。

    注意这里的矩阵和状态是相匹配的,所以下标一定从0开始

    所以矩阵乘法真正的用途在与dp,如果题目给的n很大,

    那么可以按照转移的方式来构造矩阵

    #include<bits/stdc++.h>
    #define add(a, b) a = (a + b) % mod
    #define REP(i, a, b) for(register int i = (a); i < (b); i++)
    #define _for(i, a, b) for(register int i = (a); i <= (b); i++)
    using namespace std;
    
    const int MAXN = 30;
    int next[MAXN], mod, m, n;
    char s[MAXN];
    
    struct Matrix
    {
    	int n, m;
    	int c[MAXN][MAXN];
    	
    	Matrix(int n, int m) : n(n), m(m) { memset(c, 0, sizeof(c)); }
    	
    	Matrix operator * (const Matrix& a)
    	{
    		Matrix res(n, a.m);
    		REP(i, 0, res.n)
    			REP(j, 0, res.m)
    				REP(k, 0, m)
    				{
    					res.c[i][j] += c[i][k] * a.c[k][j];
    					res.c[i][j] %= mod;
    				}
    		return res;
    	}
    };
    
    void get_next()
    {
    	next[1] = 0; int j = 0;
    	_for(i, 2, m)
    	{
    		while(j && s[j + 1] != s[i]) j = next[j];
    		if(s[j + 1] == s[i]) j++;
    		next[i] = j;
    	}
    }
    
    Matrix power(Matrix a, int b)
    {
    	Matrix res(m, m);
    	REP(i, 0, m) res.c[i][i] = 1;
    	for(; b; b >>= 1)
    	{
    		if(b & 1) res = res * a;
    		a = a * a;
    	}
    	return res;
    }
    
    int main()
    {
    	scanf("%d%d%d%s", &n, &m, &mod, s + 1);
    	get_next();
    	
    	Matrix A(m, m);
    	REP(i, 0, m)
    		REP(d, 0, 10)
    		{
    			int j = i; 
    			char ch = d + '0';
    			while(j && s[j + 1] != ch) j = next[j];
    			if(s[j + 1] == ch) j++;
    			if(j != m)add(A.c[i][j], 1);
    		}
    	
    	Matrix ans(1, m);
    	ans.c[0][0] = 1; 
    	ans = ans * power(A, n);
    	
    	int sum = 0;
    	REP(i, 0, m)
    		add(sum, ans.c[0][i]);
    	printf("%d
    ", sum);
    
    	return 0;
    }

    [SCOI2009]迷路

    首先这道题如果边权值为1的话,矩阵自乘T次就是答案

    但是这道题的边权最大为9

    所以拆成9个点。

    可以定义一个id为id(x, y) ((x - 1) * 9 + y),也就是说给每个点拆出来的点给个

    编号,然后连边的时候连编号,y为1就最原始的点,y!=1都是衍生出来的。

    注意连边的时候注意方向,一定要分清x坐标和y坐标,可以拿笔画一画

    #include<bits/stdc++.h>
    #define id(x, y) ((x - 1) * 9 + y)
    #define REP(i, a, b) for(register int i = (a); i < (b); i++)
    #define _for(i, a, b) for(register int i = (a); i <= (b); i++)
    using namespace std;
     
    const int MAXN = 100 + 10;
    const int mod = 2009;
    int n, T;
    struct Matrix
    {
    	int n, m;
    	int c[MAXN][MAXN];
    	
    	Matrix(int n, int m) : n(n), m(m) { memset(c, 0, sizeof(c)); }
    	
    	Matrix operator * (const Matrix& a)
    	{
    		Matrix res(n, a.m);
    		_for(i, 1, res.n)
    			_for(j, 1, res.m)
    				_for(k, 1, m)
    				{
    					res.c[i][j] += c[i][k] * a.c[k][j];
    					res.c[i][j] %= mod;
    				}
    		return res;
    	}
    };
    
    Matrix power(Matrix a, int b)
    {
    	Matrix res(n * 9, n * 9);
    	_for(i, 1, n * 9) res.c[i][i] = 1;
    	for(; b; b >>= 1)
    	{
    		if(b & 1) res = res * a;
    		a = a * a;
    	}
    	return res;
    }
     
    int main()
    {
    	scanf("%d%d", &n, &T);
    	Matrix A(n * 9, n * 9);
    	
    	_for(i, 1, n)
    		_for(j, 1, n)
    		{
    			int x; scanf("%1d", &x);
    			if(!x) continue;
    			A.c[id(i, x)][id(j, 1)] = 1;
    		}
    	
    	_for(i, 1, n)
    		_for(j, 1, 8)
    			A.c[id(i, j)][id(i, j + 1)] = 1;
    	
    	A = power(A, T);
    	printf("%d
    ", A.c[id(1, 1)][id(n, 1)]);
    	
    	return 0;
    }

    bzoj 1898

    我又独立做出省选题了,这次只WA了一次

    但是这次WA显然可以避免的,自己要养成写完程序静态查错的习惯,不要直接交,然后再改。

    考试的时候只能交一次。还有头脑一定要非常清晰自己在干什么。

    这道题关键在于用到了lcm的思想。

    美人鱼只有2,3,4,那么显然12秒之后又会重复。

    那么我们可以针对每一秒构造出转移矩阵,注意是每一秒,不是前几秒,我一开始写的是前几秒。

    每一秒就用dp的方式构造,这个dp非常好写。

    然后注意状态矩阵和转移矩阵要分清

    #include<bits/stdc++.h>
    #define REP(i, a, b) for(register int i = (a); i < (b); i++)
    #define _for(i, a, b) for(register int i = (a); i <= (b); i++)
    using namespace std;
      
    const int MAXN = 50 + 10;
    const int mod = 10000;
    int n, m, st, en, K, nfish;
    int g[MAXN][MAXN];
    vector<int> fish[MAXN];
     
    struct Matrix
    {
        int n, m;
        int c[MAXN][MAXN];
         
        Matrix() { memset(c, 0, sizeof(c)); }
        void init(int p) { n = m = p; }
         
        Matrix operator * (const Matrix& a)
        {
            Matrix res;
            res.n = n; res.m = a.m;
            REP(i, 0, res.n)
                REP(j, 0, res.m)
                    REP(k, 0, m)
                    {
                        res.c[i][j] += c[i][k] * a.c[k][j];
                        res.c[i][j] %= mod;
                    }
            return res;
        }
    }A[15], ans;
     
    Matrix power(Matrix a, int b)
    {
        Matrix res; res.init(n);
        REP(i, 0, n) res.c[i][i] = 1;
        for(; b; b >>= 1)
        {
            if(b & 1) res = res * a;
            a = a * a;
        }
        return res;
    }
     
    void read()
    {
        scanf("%d%d%d%d%d", &n, &m, &st, &en, &K);
        _for(i, 1, m)
        {
            int x, y; scanf("%d%d", &x, &y);
            g[x][y] = g[y][x] = 1;
        }
        scanf("%d", &nfish);
        REP(i, 0, nfish)
        {
            int x, y; scanf("%d", &x);
            while(x--)
            {
                scanf("%d", &y);
                fish[i].push_back(y);
            }
        }
    }
     
    void get_Matrix()
    {
        _for(i, 0, 12) A[i].init(n);
         
        _for(t, 1, min(12, K))
        {
            int vis[MAXN] = {0};
            REP(i, 0, nfish)
                vis[fish[i][t % fish[i].size()]] = 1;
                 
            REP(i, 0, n) if(!vis[i])
                REP(j, 0, n) if(g[i][j])
                        A[t].c[j][i]++;
        }
    }
     
    void work()
    {
        ans.n = 1; ans.m = n;
        ans.c[0][st] = 1;
    	
        Matrix t; t.init(n);
    	REP(i, 0, n) t.c[i][i] = 1; 
        if(K >= 12)
        {
            _for(i, 1, 12)  t = t * A[i];
            t = power(t, K / 12);
        }
        _for(i, 1, K % 12) t = t * A[i];
     
     	ans = ans * t;
        printf("%d
    ", ans.c[0][en]);
    }
      
    int main()
    {
        read();
        get_Matrix();
        work();
        return 0;
    }
  • 相关阅读:
    爬虫助手spider_tool-JUN
    frida 保存打印日志到本地
    frida get_frontmost_application报错
    adb shell安装证书/修改证书到系统级/
    利用celery进行分布式爬虫
    vscode Go插件安装失败解决方法,亲测2020.10.15
    Frida hook map集合遍历和修改
    frida_rpc dou音、饿le么 header加密
    Frida入门
    adb连接模拟器
  • 原文地址:https://www.cnblogs.com/sugewud/p/9819298.html
Copyright © 2011-2022 走看看