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
【题意】:给出一个n * n矩阵A和一个正整数k,求 S = A + A2 + A3 + … + Ak
【题解】:以下是matrix67的题解:
这道题两次二分,相当经典。首先我们知道,A^i可以二分求出。然后我们需要对整个题目的数据规模k进行二分。比
如,当k=6时,有:
A + A^2 + A^3 + A^4 + A^5 + A^6 =(A + A^2 + A^3) + A^3*(A + A^2 + A^3)
应用这个式子后,规模k减小了一半。我们二分求出A^3后再递归地计算A + A^2 + A^3,即可得到原问题的答案。
代码:
#include <stdio.h> #include <cstring> int n,m,k; const int N=31; int ans[N][N],A[N][N]; void add(int a[][N],int b[][N]) { for(int i=0; i<n; i++) for(int j=0; j<n; j++) { a[i][j]+=b[i][j]; if(a[i][j]>=m) a[i][j]%=m; } } void mul(int a[][N],int b[][N]) { int tmp[N][N]; for(int i=0; i<n; i++) { for(int j=0; j<n; j++) { tmp[i][j]=0; for(int k=0; k<n; k++) { tmp[i][j]+=a[i][k]*b[k][j]; if(tmp[i][j]>=m) tmp[i][j]%=m; } } } memcpy(a,tmp,sizeof(tmp)); } void pow(int a[][N],int b[][N],int x) { int tmp[N][N]; memcpy(tmp,b,sizeof(int)*N*N); for(int i=0; i<n; i++) for(int j=0; j<n; j++) { if(i==j) a[i][j]=1; else a[i][j]=0; } while(x) { if(x&1) mul(a,tmp); mul(tmp,tmp); x>>=1; } } void mat_sum(int a[][N],int b[][N],int x) { int c[N][N],d[N][N]; if(x==0) { memset(a,0,sizeof(int)*N*N); return ; } if(x==1) { memcpy(a,b,sizeof(int)*N*N); return ; } mat_sum(a,b,x>>1); pow(c,b,x>>1); memcpy(d,a,sizeof(int)*N*N); mul(a,c); add(a,d); if(x&1) { mul(c,c); mul(c,b); add(a,c); } } int main() { while(scanf("%d%d%d",&n,&k,&m)==3) { for(int i=0; i<n; i++) for(int j=0; j<n; j++) scanf("%d",&A[i][j]); mat_sum(ans,A,k); for(int i=0; i<n; i++) { printf("%d",ans[i][0]); for(int j=1; j<n; j++) { if(j<n-1) printf(" %d",ans[i][j]); else printf(" %d\n",ans[i][j]); } } } return 0; }