总结:满足下面这句话的条件,都可以考虑矩阵乘法+快速幂——把一个向量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 }