zoukankan      html  css  js  c++  java
  • [题目][蓝桥杯ALGO-60] 矩阵乘方

    一、题目

    1、题目链接

    http://lx.lanqiao.cn/problem.page?gpid=T104(需要登录且需要 VIP 账户)

    2、问题描述

    给定一个矩阵 A,一个非负整数 b 和一个正整数 m,求 A 的 b 次方除 m 的余数。

    其中一个 n x n 的矩阵除 m 的余数得到的仍是一个 n x n 的矩阵,这个矩阵的每一个元素是原矩阵对应位置上的数除m的余数。

    要计算这个问题,可以将 A 连乘 b 次,每次都对 m 求余,但这种方法特别慢,当b较大时无法使用。下面给出一种较快的算法(用 A ^ b 表示 A 的 b 次方):

    若 b = 0,则 A ^ b % m = I % m。其中 I 表示单位矩阵。

    若 b 为偶数,则 A ^ b % m = (A ^ (b / 2) % m) ^ 2 % m,即先把 A 乘 b / 2 次方对 m 求余,然后再平方后对 m 求余。

    若 b 为奇数,则 A ^ b % m = (A ^ (b - 1) % m) * a % m,即先求A乘 b - 1 次方对 m 求余,然后再乘 A 后对 m 求余。

    这种方法速度较快,请使用这种方法计算 A ^ b % m ,其中 A 是一个 2 x 2 的矩阵,m 不大于 10000。

    3、输入格式

    输入第一行包含两个整数 b, m,第二行和第三行每行两个整数,为矩阵 A。

    4、输出格式

    输出两行,每行两个整数,表示 A ^ b % m 的值。

    5、样例输入

    2 2
    1 1
    0 1

    6、样例输出

    1 0
    0 1

    二、分析与思路

    有点意思的一道基础题。

    首先这是个矩阵乘法问题,结合线性代数的知识,不难理解这个过程,并且这道题的矩阵限定为 2 * 2,就更简单了。题面给出了较快的算法,然而我完全没 get 到它想表达的,于是真就直接对 b 判断一次奇偶再分别处理,可能是蓝桥杯 OJ 里的 sb 题太多了,以为这道题也很 sb,交了一发轻松爆 0。

    然后干脆忽略掉了这个较快方法,又交了一发直接求解,90 分,最后一个点竟然 TLE,下载数据一看 b > 10 ^ 8,再回头看题,原来压根就没给出 b 的数据范围。

    大致看了下其他的博客,重新读了遍题,才意识到题面所谓的较快方法 —— 原来是在暗示快速幂。。甚至可以说是明示。题目那两句话本质是隐含了递归思想的,确实之前没做过矩阵快速幂,完全没有往这方面想。

    那么明白了需要快速幂之后,其实矩不矩阵是没啥影响的,把矩阵的乘法运算封装一下,和普通的快速幂是几乎一样的。

    三、代码

    1、常规代码

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 typedef long long ll;
     5 
     6 ll n, m, c[3][3], a[3][3], res[3][3];
     7 
     8 void multi(ll a[][3], ll b[][3]) {
     9     memset(c, 0, sizeof(c));
    10      for (int i = 1; i <= 2; i++)
    11         for (int j = 1; j <= 2; j++)
    12             for (int k = 1; k <= 2; k++) 
    13                 (c[i][j] += a[i][k] * b[k][j]) %= m;
    14     for (int i = 1; i <= 2; i++)
    15         for (int j = 1; j <= 2; j++)
    16             a[i][j] = c[i][j];
    17 }
    18 
    19 int main() {
    20     cin >> n >> m;
    21     cin >> a[1][1] >> a[1][2] >> a[2][1] >> a[2][2];
    22     if (n) {
    23         res[1][1] = a[1][1] % m, res[1][2] = a[1][2] % m;
    24         res[2][1] = a[2][1] % m, res[2][2] = a[2][2] % m;
    25         n--;
    26         while (n) {
    27             if (n & 1) multi(res, a);
    28             multi(a, a);
    29             n >>= 1;
    30         }
    31         cout << res[1][1] << ' ' << res[1][2] << endl;
    32         cout << res[2][1] << ' ' << res[2][2];
    33     }
    34     else cout << "0 0
    0 0";
    35     return 0;
    36 }

    2、矩阵封装类代码

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 typedef long long ll;
     5 
     6 ll n, m, i, j, k, l;
     7 
     8 class Matrix {
     9 public:
    10     ll a[2][2];
    11     Matrix() {}
    12     Matrix(int i, int j, int k, int l):
    13         a({{i, j}, {k, l}}) {}
    14     friend Matrix operator * (const Matrix x, const Matrix y) {
    15         Matrix t;
    16         t.a[0][0] = (x.a[0][0] * y.a[0][0] + x.a[0][1] * y.a[1][0]) % m;
    17         t.a[0][1] = (x.a[0][0] * y.a[0][1] + x.a[0][1] * y.a[1][1]) % m;
    18         t.a[1][0] = (x.a[1][0] * y.a[0][0] + x.a[1][1] * y.a[1][0]) % m;
    19         t.a[1][1] = (x.a[1][0] * y.a[0][1] + x.a[1][1] * y.a[1][1]) % m;
    20         return t;
    21     }
    22 };
    23  
    24 int main() {
    25     cin >> n >> m;
    26     cin >> i >> j >> k >> l;
    27     Matrix a(i, j, k, l), res;
    28     if (n) {
    29         res = a;
    30         n--;
    31         while (n) {
    32             if (n & 1) res = res * a;
    33             a = a * a;
    34             n >>= 1;
    35         }
    36         cout << res.a[0][0] % m << ' ' << res.a[0][1] % m << endl;
    37         cout << res.a[1][0] % m << ' ' << res.a[1][1] % m ;
    38     }
    39     else cout << "0 0
    0 0";
    40     return 0;
    41 }

    四、相关知识点

    6.2  快速幂

  • 相关阅读:
    线程安全及Python中的GIL
    八个我最常用的AS3开源类库(转)
    Mac 10.6与Win7 文件共享
    linux下erlang之OTP编译安装
    位图和矢量图区别
    让你的AIR程序脱离AIR环境运行
    outlook 0x80040201 错误
    NOSQL
    RLE压缩及优化图片压缩
    改正6种常见HTML5错误用法
  • 原文地址:https://www.cnblogs.com/jinkun113/p/13866870.html
Copyright © 2011-2022 走看看