一道英文题,自然要有优秀的故事背景和完美的题面以及简明的题意
尤达大师决定交给你和绝地大师欧比旺一项重要的任务:计算密码(尤达大师只有3个手指头,从种族发展角度,不善数学)
已知有一个n*n的矩阵和一个正整数k,根据安纳金大师的推算,密码为一个矩阵S
S = A + A^2 + A^3 + ... + A^k,最后对m取模
欧比旺大师在飞快的推算中,你看着他计算,露出了坏笑,打开了电脑敲起了整个共和国只有你会的上古语言c++...
给定n*n的矩阵和一个整数K,求S = A + A^2 + A^3 +... + A^k 对m取模的结果
显然我们可以想到一个非常暴力的解法
乘加乘加乘加......
但是很不幸,这样会Boom
这题甚至无法生成O(kn^3)的复杂度
但是我们可以注意到的是,参照等比数列,这一式子矩阵显然是等比矩阵求和,那么我们是否可以利用等比数列的某些性质或是运算加以外推得到计算的方式呢?
答案是显然的。
在等比数列求和中,设有:
S = A + A^2 + A^3 + ... + A^k
1. k % 2 == 0
S = (A + A^2 + A^3 + ... + A^k/2) + A^k/2(A + A^2 + A^3 + ... + A^k)
2. k % 2 == 1
S = (1 + A^(k/2(下取整)+1)) * (A + A^2 + ... + A^((k-1) / 2)) + A^k/2(下取整)
这样我们把这种计算方式推广到矩阵,显然我们发现这样每次可以通过二分将范围减小一半
这样我们就能够利用这种思想,递归求解矩阵
不是特别好看的代码
1 #include<iostream> 2 #include<iomanip> 3 #include<cstring> 4 #include<cstdio> 5 #include<stack> 6 #include<cmath> 7 #include<map> 8 #include<set> 9 #include<ctime> 10 #include<queue> 11 #include<vector> 12 #include<cstdlib> 13 #include<algorithm> 14 #define ll long long 15 #define uint unsigned int 16 #define ull unsigned long long 17 using namespace std; 18 struct shiki { 19 int num[35][35]; 20 }f[35], ans; 21 int n, mod, k_on_head; 22 23 inline shiki operator + (const shiki &x, const shiki &y) { 24 shiki res; 25 memset(res.num, 0, sizeof(res.num)); 26 for(int i = 1; i <= n; ++i) 27 for(int j = 1; j <= n; ++j) 28 res.num[i][j] = (x.num[i][j] + y.num[i][j]) % mod; 29 return res; 30 } 31 32 inline shiki operator * (const shiki &x, const shiki &y) { 33 shiki res; 34 memset(res.num, 0, sizeof(res.num)); 35 for(int i = 1; i <= n; ++i) 36 for(int j = 1; j <= n; ++j) 37 for(int k = 1; k <= n; ++k) 38 res.num[i][j] = (res.num[i][j] + x.num[i][k] * y.num[k][j] % mod) % mod; 39 return res; 40 } 41 42 inline shiki power(int b) { 43 shiki res; 44 memset(res.num, 0, sizeof(res.num)); 45 for(int i = 1; i <= n; ++i) res.num[i][i] = 1; 46 int cnt = 0; 47 for(; b; b >>= 1) { 48 if(b & 1) res = res * f[cnt]; 49 cnt++; 50 } 51 return res; 52 } 53 54 inline void balalalala(int kkksc03) { 55 int cnt = 1; 56 for(int i = 0; cnt <= kkksc03; ++i, cnt <<= 1) 57 f[i + 1] = f[i] * f[i]; 58 } 59 60 shiki solve(int ltt) { 61 if(ltt == 1) return f[0]; 62 shiki p = solve(ltt >> 1); 63 p = p + p * power(ltt >> 1); 64 if(ltt & 1) p = p + power(ltt); 65 return p; 66 } 67 68 inline void print(const shiki &ans) { 69 for(int i = 1; i <= n; ++i) { 70 for(int j = 1; j <= n; ++j) 71 printf("%d ", ans.num[i][j]); 72 printf(" "); 73 } 74 } 75 76 int main() { 77 scanf("%d%d%d", &n, &k_on_head, &mod); 78 for(int i = 1; i <= n; ++i) 79 for(int j = 1; j <= n; ++j) 80 scanf("%d", &f[0].num[i][j]); 81 balalalala(k_on_head);//预处理每一项 82 print(solve(k_on_head)); 83 return 0; 84 }