Matrix Power Series
Time Limit: 3000MS | Memory Limit: 131072K | |
Total Submissions: 27277 | Accepted: 11143 |
Description
Given a n × n matrix A and a positive integer k, find the sum S = A + A2 + A3 + … + Ak.
Input
The input contains exactly one test case. The first line of input contains three positive integers n (n ≤ 30), k (k ≤ 109) and m (m < 104). Then follow n lines each containing n nonnegative integers below 32,768, giving A’s elements in row-major order.
Output
Output the elements of S modulo m in the same way as A is given.
Sample Input
2 2 4 0 1 1 1
Sample Output
1 2 2 3
Source
POJ Monthly--2007.06.03, Huang, Jinsong
题意: 这题就是求一个矩阵的和式:S(k),直接对和式建立递推:
A^i是一个矩阵
很显然,把每个A^i算出来是不行的,所以我们得找找关系
因为这里牵扯到了矩阵相加求和,所以我们可以想到构建一个包含A的矩阵(只要包含A和两个一就行,这样是为了最后能得到A^1+A^2+...+A^K的式子)
其中1是单位矩阵,单位矩阵是左对角线为1的矩阵
然后容易得到:
可以看出这个分块矩阵的左下角那块就可以得到要求的解S
我们取这一块,再减去一个单位矩阵1即可。
参考博客:https://www.cnblogs.com/pdev/p/4063669.html
#include <map> #include <set> #include <stack> #include <cmath> #include <queue> #include <cstdio> #include <vector> #include <string> #include <cstring> #include <iostream> #include <algorithm> #define debug(a) cout << #a << " " << a << endl using namespace std; const int maxn = 110; const int mod = 2; typedef long long ll; struct matrix { ll a[maxn][maxn]; }; matrix base, ans; ll n, t, m; matrix multip( matrix x, matrix y ) { matrix tmp; for( ll i = 0; i < 2*n; i ++ ) { for( ll j = 0; j < 2*n; j ++ ) { tmp.a[i][j] = 0; for( ll k = 0; k < 2*n; k ++ ) { tmp.a[i][j] = ( tmp.a[i][j] + x.a[i][k] * y.a[k][j] ) % m; } } } return tmp; } void f( ll x ) { while( x ) { if( x&1 ) { ans = multip( ans, base ); } base = multip( base, base ); x /= 2; } } int main() { while( cin >> n >> t >> m ) { memset( ans.a, 0, sizeof(ans.a) ); memset( base.a, 0, sizeof(base.a) ); for( ll i = 0; i < n; i ++ ) { for( ll j = 0; j < n; j ++ ) { cin >> base.a[i][j]; } } for( ll i = n; i < 2*n; i ++ ) { //两个单位矩阵 base.a[i][i-n] = base.a[i][i] = 1; } //上面两个for循环是为了构建出新的包含A的矩阵 for( ll i = 0; i < 2*n; i ++ ) { ans.a[i][i] = 1; } f(t+1); //由上面举的例子可以看出要求出n次方,得算n+1次 for( ll i = n; i < 2*n; i ++ ) { for( ll j = 0; j < n; j ++ ) { if( i == j+n ) { ans.a[i][j] --; } if( j != n-1 ) { cout << ( ans.a[i][j] + m ) % m << " "; } else { cout << ( ans.a[i][j] + m ) % m << endl; } } } } return 0; }