http://poj.org/problem?id=3233
题目大意:给定矩阵A,求A + A^2 + A^3 + … + A^k的结果(两个矩阵相加就是对应位置分别相加)。输出的数据mod m。k<=10^9。
这道题两次二分,相当经典。首先我们知道,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 <iostream> #include <algorithm> #include <cstdio> #include <cstring> #include <math.h> #include <queue> using namespace std; struct matrix { int a[31][31]; } init,res; int n,k,mod; matrix Mult(matrix x,matrix y) { matrix tmp; for(int i=0; i<n; i++) { for(int j=0; j<n; j++) { tmp.a[i][j]=0; for(int k=0; k<n; k++) tmp.a[i][j]=(tmp.a[i][j]+x.a[i][k]*y.a[k][j])%mod; } } return tmp; } matrix Pow(matrix x,int k) { matrix tmp; for(int i=0; i<n; i++) { for(int j=0; j<n; j++) tmp.a[i][j]=(i==j); } while(k) { if(k&1) tmp=Mult(tmp,x); k>>=1; x=Mult(x,x); } return tmp; } matrix Add(matrix x,matrix y) { matrix tmp; for(int i=0; i<n; i++) { for(int j=0; j<n; j++) { tmp.a[i][j]=(x.a[i][j]+y.a[i][j])%mod; } } return tmp; } matrix Sum(matrix x,int k) { if(k==1) return x; matrix tmp=Sum(x,k/2),y; if(k&1) { y=Pow(x,k/2+1); tmp=Add(Mult(y,tmp),tmp); return Add(tmp,y); } else { y=Pow(x,k/2); return Add(Mult(y,tmp),tmp); } } int main() { while(scanf("%d%d%d",&n,&k,&mod)!=EOF) { for(int i=0; i<n; i++) { for(int j=0; j<n; j++) { scanf("%d",&init.a[i][j]); init.a[i][j]%=mod; } } res=Sum(init,k); for(int i=0; i<n; i++) { for(int j=0; j<n; j++) { if(j==0) printf("%d",res.a[i][j]); else printf(" %d",res.a[i][j]); } printf(" "); } } return 0; }
其他大神的想法:
题目分析:矩阵快速幂。首先我们知道 A^x 可以用矩阵快速幂求出来。其次可以对k进行二分,每次将规模减半,分k为奇偶两种情况,如当k = 6和k = 7时有:
k = 6 有: S(6) = (1 + A^3) * (A + A^2 + A^3) = (1 + A^3) * S(3)。
k = 7 有: S(7) = A + (A + A^4) * (A + A^2 + A^3) = A + (A + A^4) * S(3)。
ps:对矩阵定义成结构体Matrix,求S时用递归,程序会比较直观,好写一点。当然定义成数组,然后再进行一些预处理,效率会更高些。