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
解题思路:等比矩阵求和,采用递归二分的方法。
上图就给出了求前k项等比矩阵的和的递推式,解法采用递归来求和比较直观,也很好理解。
AC代码(1704ms):
1 #include<iostream> 2 #include<cstring> 3 using namespace std; 4 const int maxn=35; 5 int n,k,mod; 6 struct Matrix{int m[maxn][maxn];}init; 7 Matrix add(Matrix a,Matrix b){//矩阵加法 8 Matrix c; 9 for(int i=0;i<n;++i) 10 for(int j=0;j<n;++j) 11 c.m[i][j]=(a.m[i][j]+b.m[i][j])%mod; 12 return c; 13 } 14 Matrix mul(Matrix a,Matrix b){//矩阵乘法 15 Matrix c; 16 for(int i=0;i<n;i++){ 17 for(int j=0;j<n;j++){ 18 c.m[i][j]=0; 19 for(int k=0;k<n;k++) 20 c.m[i][j]=(c.m[i][j]+a.m[i][k]*b.m[k][j])%mod; 21 } 22 } 23 return c; 24 } 25 Matrix quick_power(Matrix a,int x){//矩阵快速幂 26 Matrix b;memset(b.m,0,sizeof(b.m)); 27 for(int i=0;i<n;++i)b.m[i][i]=1;//单位矩阵 28 while(x){ 29 if(x&1)b=mul(b,a); 30 a=mul(a,a);x>>=1; 31 } 32 return b; 33 } 34 Matrix sum(Matrix s,int k){//求前k项和 35 if(k==1)return s;//递归出口:当幂指数为1时,返回当前的矩阵 36 Matrix tmp;memset(tmp.m,0,sizeof(tmp.m));//暂存保存中间的矩阵 37 for(int i=0;i<n;++i)tmp.m[i][i]=1;//单位矩阵 38 tmp=add(tmp,quick_power(s,k>>1));//计算1+A^{k/2} 39 tmp=mul(tmp,sum(s,k>>1));//计算(1+A^{k/2})*(A + A^2 + A^3 + … + A^{k/2})=(1+A^{k/2})*(S_{k/2}) 40 if(k&1)tmp=add(tmp,quick_power(s,k));//若k是奇数,则加上A^k 41 return tmp;//返回前k项的值 42 } 43 void print_rectangle(Matrix r){ 44 for(int i=0;i<n;++i) 45 for(int j=0;j<n;++j) 46 cout<<r.m[i][j]<<((j==n-1)?" ":" "); 47 } 48 int main(){ 49 while(cin>>n>>k>>mod){ 50 for(int i=0;i<n;++i) 51 for(int j=0;j<n;++j) 52 cin>>init.m[i][j]; 53 init=sum(init,k); 54 print_rectangle(init); 55 } 56 return 0; 57 }
矩阵中套矩阵,效率上比上一种方法更快,实际上是2n×2n的矩阵快速幂。就样例展开等式左边的矩阵:
那么最终的答案就是等式右边矩阵中左下角的子矩阵减去单位矩阵,注意某个元素值减-1之后可能为-1,那么此时只需再加上mod即可。
AC代码(610ms):
1 #include<iostream> 2 #include<cstring> 3 using namespace std; 4 const int maxn=70; 5 struct Matrix{int m[maxn][maxn];}init; 6 int n,k,mod; 7 Matrix mul(Matrix a,Matrix b){//矩阵乘法 8 Matrix c; 9 for(int i=0;i<2*n;i++){//矩阵大小扩大两倍,枚举第一个矩阵的行 10 for(int j=0;j<2*n;j++){//枚举第二个矩阵的列 11 c.m[i][j]=0; 12 for(int k=0;k<2*n;k++)//枚举第一个矩阵的列 13 c.m[i][j]=(c.m[i][j]+a.m[i][k]*b.m[k][j])%mod; 14 } 15 } 16 return c; 17 } 18 Matrix POW(Matrix a,int x){//矩阵快速幂 19 Matrix b;memset(b.m,0,sizeof(b.m)); 20 for(int i=0;i<2*n;++i)b.m[i][i]=1;//构造单位矩阵 21 while(x){ 22 if(x&1)b=mul(b,a); 23 a=mul(a,a);x>>=1; 24 } 25 return b; 26 } 27 void print_rectangle(Matrix r){ 28 for(int i=0;i<n;++i){ 29 for(int j=0;j<n;++j){ 30 if(i==j)r.m[n+i][j]-=1; 31 if(r.m[n+i][j]<0)r.m[n+i][j]+=mod;//左下角子矩阵减去单位矩阵,减完可能小于0,因此需要加上mod再取余mod 32 cout<<r.m[n+i][j]<<((j==n-1)?' ':' '); 33 } 34 } 35 } 36 int main(){ 37 while(cin>>n>>k>>mod){ 38 memset(init.m,0,sizeof(init.m));//全部初始化为0 39 for(int i=0;i<n;++i){//首先初始化矩阵 40 for(int j=0;j<n;++j) 41 cin>>init.m[i][j]; 42 init.m[n+i][i]=init.m[n+i][n+i]=1;//其余是单位矩阵 43 } 44 init=POW(init,k+1);//求其前k+1项和(左下角包含单位矩阵,最后输出要减去单位矩阵) 45 print_rectangle(init);//打印等比矩阵A前k项和 46 } 47 return 0; 48 }