矩阵快速幂各类题型总结(一般,共轭,1 * n, 矩阵简化)

Reading comprehension

这个不难找出递推式 f [ n ] = f [ n − 1 ] + 2 f [ n − 2 ] + 1 f[n] = f[n - 1] + 2f[n - 2] + 1 f[n]=f[n1]+2f[n2]+1

/*
  Author : lifehappy
*/
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

const int inf = 0x3f3f3f3f;
const double eps = 1e-7;

ll n, mod;

struct matrix {
    ll a[3][3];
};

matrix operator * (matrix a, matrix b) {
    matrix ans;
    for(int i = 0; i < 3; i++) {
        for(int j = 0; j < 3; j++) {
            ans.a[i][j] = 0;
            for(int k = 0; k < 3; k++) {
                ans.a[i][j] = (ans.a[i][j] + 1ll * a.a[i][k] * b.a[k][j] % mod) % mod;
            }
        }
    }
    return ans;
}

int main() {
    // freopen("in.txt", "r", stdin);
    // freopen("out.txt", "w", stdout);
    // ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    while(scanf("%lld %lld", &n, &mod) != EOF && (n + mod)) {
        if(n <= 2) {
            if(n == 1) printf("%d\n", 1 % mod);
            else printf("%d\n", 2 % mod);
            continue;
        }
        matrix ans = {2, 1, 1,
                      0, 0, 0,
                      0, 0, 0};
        matrix a = {1, 1, 0,
                    2, 0, 0, 
                    1, 0, 1};
        n -= 2;
        while(n) {
            if(n & 1) ans = ans * a;
            a = a * a;
            n >>= 1;
        }
        printf("%lld\n", ans.a[0][0]);
    }
	return 0;
}

233 Matrix

这里直接写出构造的矩阵了。
A = [ a 00 a 10 a 20 … a ( n − 1 ) 0 a n 0 1 0 … 0 … ] A =\left[\begin{matrix} a_{00}&a_{10}&a_{20}\dots a_{(n - 1)0}&a_{n0}&1\\ 0& \dots\\ 0& \dots\\ \end{matrix}\right] A=a0000a10a20a(n1)0an01
整体来说就是一个 ( n + 2 ) × ( n + 2 ) (n + 2) \times(n + 2) (n+2)×(n+2)的矩阵吧。
B = [ 10 10 10 … 10 10 0 0 1 1 … 1 1 0 0 0 1 … 1 1 0 … 3 3 3 … 3 3 1 ] B =\left[ \begin{matrix} 10&10&10 \dots 10&10&0\\ 0&1&1 \dots 1&1&0\\ 0&0&1\dots1&1&0\\ \dots\\ 3&3&3\dots3&3&1\\ \end{matrix} \right] B=10003101031010111133101130001
同样的也是一个 ( n + 2 ) × ( n + 2 ) (n + 2) \times(n + 2) (n+2)×(n+2)的矩阵。

我们个 a 00 a_{00} a00初始化为 23 23 23,这个时候 A × B A \times B A×B发现 A A A中的元素会变成第二列的,所以这里就形成了一个递推式了,只要跑一跑矩阵快速幂即可。

/*
  Author : lifehappy
*/
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

const int inf = 0x3f3f3f3f;
const double eps = 1e-7;

const int mod = 10000007;

int n, m;

struct matrix {
    ll a[15][15];
    void init() {
        memset(a, 0, sizeof a);
    }
};

matrix operator * (matrix a, matrix b) {
    matrix ans;
    for(int i = 0; i < n; i++) {
        for(int j = 0; j < n; j++) {
            ans.a[i][j] = 0;
            for(int k = 0; k < n; k++) {
                ans.a[i][j] = (ans.a[i][j] + 1ll * a.a[i][k] * b.a[k][j] % mod) % mod;
            }
        }
    }
    return ans;
}

int main() {
    // freopen("in.txt", "r", stdin);
    // freopen("out.txt", "w", stdout);
    // ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    while(scanf("%d %d", &n, &m) != EOF) {
        matrix ans, a;
        ans.init(), a.init();
        for(int i = 1; i <= n; i++) scanf("%lld", &ans.a[0][i]);
        ans.a[0][0] = 23, ans.a[0][n + 1] = 1;
        for(int i = 0; i <= n; i++) {
            a.a[0][i] = 10;
            a.a[n + 1][i] = 3;
        }
        a.a[n + 1][n + 1] = 1;
        for(int i = 1; i <= n; i++) {
            for(int j = i; j <= n; j++) {
                a.a[i][j] = 1;
            }
        }
        n += 2;
        while(m) {
            if(m & 1) ans = ans * a;
            a = a * a;
            m >>= 1;
        }
        printf("%lld\n", ans.a[0][n - 2]);
    }
	return 0;
}

B. Jzzhu and Sequences

裸题 f n = f n − 1 − f n − 2 f_n = f_{n - 1} - f_{n - 2} fn=fn1fn2

/*
  Author : lifehappy
*/
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

const int inf = 0x3f3f3f3f;
const double eps = 1e-7;

const int mod = 1e9 + 7;

int n = 2, m;

struct matrix {
    ll a[2][2];
    void init() {
        memset(a, 0, sizeof a);
    }
};

matrix operator * (matrix a, matrix b) {
    matrix ans;
    for(int i = 0; i < n; i++) {
        for(int j = 0; j < n; j++) {
            ans.a[i][j] = 0;
            for(int k = 0; k < n; k++) {
                ans.a[i][j] = (ans.a[i][j] + 1ll * a.a[i][k] * b.a[k][j] % mod) % mod;
            }
        }
    }
    return ans;
}

int main() {
    // freopen("in.txt", "r", stdin);
    // freopen("out.txt", "w", stdout);
    // ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    ll x, y, n;
    scanf("%lld %lld %lld", &x, &y, &n);
    if(n <= 2) {
        if(n == 1) printf("%d\n", (x % mod + mod) % mod);
        else printf("%d\n", (y % mod + mod) % mod);
        return 0;
    }
    matrix ans = {
        y, x, 
        0, 0
    };
    matrix a = {
        1, 1,
        -1, 0
    };
    n -= 2;
    while(n) {
        if(n & 1) ans = ans * a;
        a = a * a;
        n >>= 1;
    }
    printf("%lld", (ans.a[0][0] % mod + mod) % mod);
	return 0;
}

M斐波那契数列

这是个乘法的递推式,显然乘法可以变成指数相加,所以还是一个矩阵快速幂,统计最后一项有多少个 A 0 , A 1 A_0,A_1 A0,A1即可。

当然矩阵中的取模得用费马小定理。

/*
  Author : lifehappy
*/
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

const int inf = 0x3f3f3f3f;
const double eps = 1e-7;

const int mod = 1000000006;

int n = 4, m;

struct matrix {
    ll a[4][4];
    void init() {
        memset(a, 0, sizeof a);
    }
};

matrix operator * (matrix a, matrix b) {
    matrix ans;
    for(int i = 0; i < n; i++) {
        for(int j = 0; j < n; j++) {
            ans.a[i][j] = 0;
            for(int k = 0; k < n; k++) {
                ans.a[i][j] = (ans.a[i][j] + 1ll * a.a[i][k] * b.a[k][j] % mod) % mod;
            }
        }
    }
    return ans;
}

ll quick_pow(ll a, int n) {
    ll ans = 1;
    const int mod = 1e9 + 7;
    while(n) {
        if(n & 1) ans = ans * a % mod;
        a = a * a % mod;
        n >>= 1;
    }
    return ans;
}

int main() {
    // freopen("in.txt", "r", stdin);
    // freopen("out.txt", "w", stdout);
    // ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    ll x, y, n;
    while(scanf("%lld %lld %lld", &x, &y, &n) != EOF) {
        const int mod = 1e9 + 7;
        if(n <= 1) {
            if(n == 0) {
                printf("%lld\n", x % mod);
            }
            else {
                printf("%lld\n", y % mod);
            }
            continue;
        }
        matrix ans = {
            1, 0, 0, 1,
            0, 0, 0, 0,
            0, 0, 0, 0,
            0, 0, 0, 0
        };
        matrix a = {
            1, 0, 1, 0,
            0, 1, 0, 1,
            1, 0, 0, 0,
            0, 1, 0, 0
        };
        n -= 1;
        while(n) {
            if(n & 1) ans = ans * a;
            a = a * a;
            n >>= 1;
        }
        ll res = 1ll * quick_pow(x, ans.a[0][1]) * quick_pow(y, ans.a[0][0]) % mod;
        printf("%lld\n", res);
    }
	return 0;
}

So Easy!

共轭矩阵构造的经典题了。

假设 A n = ( a + b ) n , B n = ( a − b ) n A_n = (a + \sqrt b) ^n,B_n = (a - \sqrt b) ^n An=(a+b )n,Bn=(ab )n,一定有 A n + B n A_n + B_n An+Bn是个有理数

并且有 B n < 1 B_n < 1 Bn<1,所以有 ⌈ S n ⌉ = A n + B n \lceil S_n \rceil = A_n + B_n Sn=An+Bn

2 a S n = ( ( a + b ) n + ( a − b ) n ) ( ( a + b ) + ( a − b ) ) = S n + 1 + ( a 2 − b ) S n − 1 2aS_n = ((a + \sqrt b) ^n + (a - \sqrt b) ^n)((a + \sqrt b) + (a - \sqrt b)) = S_{n + 1} +(a ^2 - b)S_{n - 1} 2aSn=((a+b )n+(ab )n)((a+b )+(ab ))=Sn+1+(a2b)Sn1

得到 S n = 2 a S n − 1 + ( b − a 2 ) S n − 2 S_n = 2aS_{n - 1} +(b - a ^ 2)S_{n - 2} Sn=2aSn1+(ba2)Sn2,于是递推式就得到了进行矩阵快速幂即可。

/*
  Author : lifehappy
*/
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

const int inf = 0x3f3f3f3f;
const double eps = 1e-7;

// const int mod = 1000000006;

ll n = 2, mod;

struct matrix {
    ll a[2][2];
    void init() {
        memset(a, 0, sizeof a);
    }
};

matrix operator * (matrix a, matrix b) {
    matrix ans;
    for(int i = 0; i < n; i++) {
        for(int j = 0; j < n; j++) {
            ans.a[i][j] = 0;
            for(int k = 0; k < n; k++) {
                ans.a[i][j] = (ans.a[i][j] + 1ll * a.a[i][k] * b.a[k][j] % mod) % mod;
            }
        }
    }
    return ans;
}

int main() {
    // freopen("in.txt", "r", stdin);
    // freopen("out.txt", "w", stdout);
    // ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    ll a, b, n;
    while(scanf("%lld %lld %lld %lld", &a, &b, &n, &mod) != EOF) {
        ll a1 = 2ll * a % mod, a2 = 2ll * (a * a % mod + b) % mod;
        if(n <= 2) {
            if(n == 1) printf("%lld\n", a1);
            else printf("%lld\n", a2);
            continue;
        }
        n -= 2;
        matrix ans = {
            a2, a1, 
            0, 0
        };
        matrix fat = {
            2ll * a % mod, 1,
            ((b - a * a % mod) % mod + mod) % mod, 0
        };
        while(n) {
            if(n & 1) ans = ans * fat;
            fat = fat * fat;
            n >>= 1;
        }
        printf("%lld\n", ans.a[0][0]);
    }
	return 0;
}

Problem of Precision

这道题目是向下取整,跟上一道题目一样构造,唯一的不同就是 S n = A n + B n − 1 S_n = A_n + B_n - 1 Sn=An+Bn1,所以我们还是按照 S n S_n Sn递推,最后在答案上减一即可。

/*
  Author : lifehappy
*/
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

const int inf = 0x3f3f3f3f;
const double eps = 1e-7;

const int mod = 1024;

int n = 2;

struct matrix {
    ll a[2][2];
    void init() {
        memset(a, 0, sizeof a);
    }
};

matrix operator * (matrix a, matrix b) {
    matrix ans;
    for(int i = 0; i < n; i++) {
        for(int j = 0; j < n; j++) {
            ans.a[i][j] = 0;
            for(int k = 0; k < n; k++) {
                ans.a[i][j] = (ans.a[i][j] + 1ll * a.a[i][k] * b.a[k][j] % mod) % mod;
            }
        }
    }
    return ans;
}

int main() {
    // freopen("in.txt", "r", stdin);
    // freopen("out.txt", "w", stdout);
    // ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    int T;
    scanf("%d", &T);
    while(T--) {
        ll n;
        scanf("%lld", &n);
        ll a1 = 10, a2 = 98;
        if(n <= 2) {
            if(n == 1) printf("%lld\n", (a1 - 1) % mod);
            else printf("%lld\n", (a2 - 1) % mod);
            continue;
        }
        n -= 2;
        matrix ans = {
            a2, a1,
            0, 0
        };
        matrix fat = {
            10, 1,
            1023, 0
        };
        while(n) {
            if(n & 1) ans = ans * fat;
            fat = fat * fat;
            n >>= 1;
        }
        printf("%lld\n", (ans.a[0][0] - 1 + mod) % mod);
    }
	return 0;
}

C. Partial Sums

由于递推矩阵的特殊关系,所以可以转化为 1 × n 1 \times n 1×n的矩阵递推,最后达到 n 2 l o g ( n ) n ^ 2log(n) n2log(n)的复杂度。

/*
  Author : lifehappy
*/
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

const int inf = 0x3f3f3f3f;
const double eps = 1e-7;

const int N = 2e3 + 10, mod = 1e9 + 7;

int n, k;

struct matrix {
    ll a[N];
};

matrix operator * (matrix a, matrix b) {
    matrix ans;
    for(int i = 1; i <= n; i++) {
        ans.a[i] = 0;
        for(int j = 1; j <= i; j++) {
            ans.a[i] = (ans.a[i] + a.a[j] * b.a[i - j + 1] % mod) % mod;
        }
    }
    return ans;
}

int main() {
    // freopen("in.txt", "r", stdin);
    // freopen("out.txt", "w", stdout);
    // ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    scanf("%d %d", &n, &k);
    matrix ans, a;
    for(int i = 1; i <= n; i++) {
        scanf("%d", &ans.a[i]);
        a.a[i] = 1;
    }
    while(k) {
        if(k & 1) ans = ans * a;
        a = a * a;
        k >>= 1;
    }
    for(int i = 1; i <= n; i++) {
        printf("%lld%c", ans.a[i], i == n ? '\n' : ' ');
    }
	return 0;
}

Fast Matrix Calculation

A B n 2 = A ( B A ) n 2 − 1 B AB^{n^2} = A(BA)^{n^2 - 1}B ABn2=A(BA)n21B,转化为 k × k k \times k k×k的矩阵快速幂,这样就可以保证不超时了。

/*
  Author : lifehappy
*/
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

const int inf = 0x3f3f3f3f;
const double eps = 1e-7;

const int N = 1e3 + 10, mod = 6;

int n, m;

struct matrix {
    ll a[6][6];
    void init() {
        memset(a, 0, sizeof a);
    }
}c;

struct Matrix {
    ll a[N][N];
}a, b, Ans1, Ans2;

matrix operator * (matrix a, matrix b) {
    matrix ans;
    for(int i = 0; i < m; i++) {
        for(int j = 0; j < m; j++) {
            ans.a[i][j] = 0;
            for(int k = 0; k < m; k++) {
                ans.a[i][j] = (ans.a[i][j] + a.a[i][k] * b.a[k][j] % mod) % mod;
            }
        }
    }
    return ans;
}

matrix mult() {
    matrix ans;
    for(int i = 0; i < m; i++) {
        for(int j = 0; j < m; j++) {
            ans.a[i][j] = 0;
            for(int k = 0; k < n; k++) {
                ans.a[i][j] = (ans.a[i][j] + b.a[i][k] * a.a[k][j] % mod) % mod;
            }
        }
    }
    return ans;
}

int main() {
    // freopen("in.txt", "r", stdin);   
    // freopen("out.txt", "w", stdout);
    // ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    while(scanf("%d %d", &n, &m) && (n + m)) {
        for(int i = 0; i < n; i++) {
            for(int j = 0; j < m; j++) {
                scanf("%lld", &a.a[i][j]);
            }
        }
        for(int i = 0; i < m; i++) {
            for(int j = 0; j < n; j++) {
                scanf("%lld", &b.a[i][j]);
            }
        }
        c = mult();
        matrix ans;
        ans.init();
        for(int i = 0; i < m; i++) ans.a[i][i] = 1;
        int n1 = n * n - 1;
        while(n1) {
            if(n1 & 1) ans = ans * c;
            c = c * c;
            n1 >>= 1;
        }
        for(int i = 0; i < n; i++) {
            for(int j = 0; j < m; j++) {
                Ans1.a[i][j] = 0;
                for(int k = 0; k < m; k++) {
                    Ans1.a[i][j] = (Ans1.a[i][j] + a.a[i][k] * ans.a[k][j] % mod) % mod;
                }
            }
        }
        for(int i = 0; i < n; i++) {
            for(int j = 0; j < n; j++) {
                Ans2.a[i][j] = 0;
                for(int k = 0; k < m; k++) {
                    Ans2.a[i][j] = (Ans2.a[i][j] + Ans1.a[i][k] * b.a[k][j] % mod) % mod;
                }
            }
        }
        int res = 0;
        for(int i = 0; i < n; i++) {
            for(int j = 0; j < n; j++) {
                res += Ans2.a[i][j];
            }
        }
        printf("%d\n", res);
    }
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值