矩阵和线性方程组
总结:满足下面这句话的条件,都可以考虑矩阵乘法+快速幂——把一个向量v变成另一个向量v',并且v'的每一个分量都是v的各个分量的线性组合。
1、UVa 10870, Recurrences
题意:给出递推关系f(n) = a1*f(n-1) + a2*f(n-2)....ad*f(n-d),给出d, n, m, a1, a2, ...ad, f(1), f(2)...f(n-d),求f(n) % m。
解法:矩阵乘法+快速幂。这是我第一次做矩阵乘法的题,由于是专题训练,一上来就构造成f(n) = G * F(n-1),只需要G = [a1, a2,...ad],F(n-1) = [f(n-1), f(n-2),...f(n-d)]T即可。
但是,这样构造显然是不对的,我们要构造出的灯式形势应该是这样的(矩阵)F(n) = (d*d的矩阵)G * (矩阵)F(n-1),只有这样的形式(G为d*d),才能使用矩阵乘法快速幂。
所以,F(n) = [f(n-d), f(n-d+1),...f(n-1)]T,
G = [0 1 ]
[ 0 1 ]
[... ... ]
[ 0 1]
[ad a(d-1).... a2 a1] (d*d的矩阵)
构造出来,这道题便得以解决。
tag:math, matrix
1 /* 2 * Author: Plumrain 3 * Created Time: 2013-09-10 21:16 4 * File Name: math-UVa-10870.cpp 5 */ 6 #include<iostream> 7 #include<cstdio> 8 #include<cstring> 9 10 using namespace std; 11 12 #define CLR(x) memset(x, 0, sizeof(x)) 13 #define out(x) cout<<#x<<":"<<(x)<<endl 14 #define tst(a) cout<<#a<<endl 15 16 typedef int matrix[20][20]; 17 18 const int N = 15; 19 int mod; 20 int a[N+5], f[N+5]; 21 22 void mtx_init (matrix& A, int n) 23 { 24 CLR (A); 25 for (int i = 0; i < (n-1); ++ i) 26 A[i][i+1] = 1; 27 for (int i = 0; i < n; ++ i) 28 A[n-1][i] = a[n-i]; 29 } 30 31 void mtx_mul (matrix& A, matrix B, int n) 32 { 33 matrix ret; 34 CLR (ret); 35 for (int i = 0; i < n; ++ i) 36 for (int k = 0; k < n; ++ k) 37 for (int j = 0; j < n; ++ j) 38 ret[i][k] = (((A[i][j] * B[j][k]) % mod) + ret[i][k]) % mod; 39 40 for (int i = 0; i < n; ++ i) 41 for (int j = 0; j < n; ++ j) 42 A[i][j] = ret[i][j]; 43 } 44 void mtx_pow (matrix& A, int num, int n) 45 { 46 matrix ret; 47 CLR (ret); 48 for (int i = 0; i < n; ++ i) 49 ret[i][i] = 1; 50 while (num > 0){ 51 if (num & 1) 52 mtx_mul (ret, A, n); 53 num >>= 1; 54 mtx_mul (A, A, n); 55 } 56 57 for (int i = 0; i < n; ++ i) 58 for (int j = 0; j < n; ++ j) 59 A[i][j] = ret[i][j]; 60 } 61 62 int gao (int m, int n) 63 { 64 matrix A; 65 mtx_init (A, n); 66 67 mtx_pow (A, m-n, n); 68 int ret = 0; 69 for (int i = 0; i < n; ++ i) 70 ret = (((A[n-1][i] * f[i+1]) % mod) + ret) % mod; 71 if (ret < 0) ret += mod; 72 return ret; 73 } 74 75 int main() 76 { 77 int n, m; 78 while (scanf ("%d%d%d", &n, &m, &mod) != EOF && n){ 79 for (int i = 1; i <= n; ++ i){ 80 scanf ("%d", &a[i]); 81 a[i] %= mod; 82 } 83 for (int i = 1; i <= n; ++ i){ 84 scanf ("%d", &f[i]); 85 f[i] %= mod; 86 } 87 88 if (m <= n) printf ("%d\n", f[m]); 89 else printf ("%d\n", gao (m, n)); 90 } 91 return 0; 92 }
2、NEERC 2006, LA 3704, Cellular Automaton
题意:一个环上有n个点,标号依次为0,1...n-1。每次操作后,每个点的值都将变为,与它距离小于等于d的所有点在操作之前的值之和mod m的值。给定n, m, d, k和n个格子各自的值,求经过k次操作之后每个格子的值。
解法:
tag:math, circulant matrix,
1 /* 2 * Author: Plumrain 3 * Created Time: 2013-09-13 12:59 4 * File Name: math-NEERC2006-LA3704.cpp 5 */ 6 #include<iostream> 7 #include<cstdio> 8 #include<cstring> 9 10 using namespace std; 11 12 #define CLR(x) memset(x, 0, sizeof(x)) 13 14 const int N = 500; 15 16 typedef long long int64; 17 typedef int64 matrix[N+5]; 18 19 int n, mod, d, k; 20 int64 a[N+5]; 21 int64 A[N+5]; 22 23 void mtx_mul(matrix& A, matrix B) 24 { 25 matrix ret; 26 CLR (ret); 27 for (int i = 0; i < n; ++ i) 28 for (int j = 0, pos = i; j < n; ++ j, pos=(pos-1+n)%n) 29 ret[i] = ((A[j] * B[pos]) % mod + ret[i]) % mod; 30 31 for (int i = 0; i < n; ++ i) 32 A[i] = ret[i]; 33 } 34 35 void mtx_pow(matrix& A, int num) 36 { 37 if (num == 1) return; 38 39 matrix ret; 40 for (int i = 0; i < n; ++ i) 41 ret[i] = A[i]; 42 -- num; 43 44 while (num > 0){ 45 if (num & 1) mtx_mul (ret, A); 46 num >>= 1; 47 mtx_mul (A, A); 48 } 49 50 for (int i = 0; i < n; ++ i) 51 A[i] = ret[i]; 52 } 53 54 void gao() 55 { 56 CLR (A); 57 int pos1 = 0, pos2 = 0; 58 int cnt = 0; 59 while (cnt <= d){ 60 A[pos1] = 1; A[pos2] = 1; 61 62 ++ cnt; 63 pos1 = (pos1+1) % n; 64 pos2 = (pos2-1+n) % n; 65 } 66 67 mtx_pow(A, k); 68 69 for (int i = 0; i < n; ++ i){ 70 int64 x = 0; 71 for (int j = 0; j < n; ++ j) 72 x = ((A[(j-i+n)%n]*a[j]) % mod + x) % mod; 73 74 printf ("%lld", x); 75 if (i != n-1) printf (" "); 76 } 77 printf ("\n"); 78 } 79 80 int main() 81 { 82 while (scanf ("%d", &n) != EOF){ 83 scanf ("%d%d%d", &mod, &d, &k); 84 for (int i = 0; i < n; ++ i) 85 scanf ("%lld", &a[i]); 86 87 gao (); 88 } 89 return 0; 90 }
3、POJ 3070 Fibonacci
题意:对于Fibonacci数列,“0, 1, 1, 2, 3, 5, 8, 13, 21, 34, …”,(F0 = 0)可以用矩阵的方法求得Fn。给n,求Fn。
解法:本来,如果直接说给n求Fn,这道题还是很有价值的。但是题目不仅仅是直接说了用矩阵求,甚至直接将给出如下图片:
这道题就直接按照这个图片写就好了.....
Ps:用矩阵求类似问题的构造方法,还有就是刘汝佳书上写的那种构造方法,那个是通用的。即本篇文章第一题。
tag:math, matrix, good
1 /* 2 * Author: Plumrain 3 * Created Time: 2013-10-14 15:42 4 * File Name: math-POJ-3070.cpp 5 */ 6 #include<iostream> 7 #include<cstdio> 8 #include<cstring> 9 10 using namespace std; 11 12 #define CLR(x) memset(x, 0, sizeof(x)) 13 const int mod = 10000; 14 typedef int matrix[10][10]; 15 16 void mtx_mul(matrix& A, matrix B) 17 { 18 matrix ret; CLR (ret); 19 for (int i = 0; i < 2; ++ i) 20 for (int j = 0; j < 2; ++ j){ 21 ret[i][j] = 0; 22 for (int k = 0; k < 2; ++ k) 23 ret[i][j] = (A[i][k] * B[k][j] + ret[i][j]) % mod; 24 } 25 26 for (int i = 0; i < 2; ++ i) 27 for (int j = 0; j < 2; ++ j) 28 A[i][j] = ret[i][j]; 29 } 30 31 void mtx_pow(matrix& A, int n) 32 { 33 -- n; 34 matrix ret; CLR (ret); 35 for (int i = 0; i < 2; ++ i) 36 for (int j = 0; j < 2; ++ j) 37 ret[i][j] = A[i][j]; 38 while (n > 0){ 39 if (n & 1) mtx_mul(ret, A); 40 n >>= 1; 41 mtx_mul(A, A); 42 } 43 for (int i = 0; i < 2; ++ i) 44 for (int j = 0; j < 2; ++ j) 45 A[i][j] = ret[i][j]; 46 } 47 48 int main() 49 { 50 int n; 51 while (scanf ("%d", &n) != EOF && n != -1){ 52 matrix A; CLR (A); 53 A[0][0] = 1; A[0][1] = 1; A[1][0] = 1; 54 if (n < 4){ 55 if (!n) printf ("0\n"); 56 if (n == 1 || n == 2) printf ("1\n"); 57 if (n == 3) printf ("2\n"); 58 continue; 59 } 60 mtx_pow(A, n); 61 printf ("%d\n", A[0][1] % mod); 62 } 63 return 0; 64 }
现在的你,在干什么呢?
你是不是还记得,你说你想成为岩哥那样的人。