题目链接:http://poj.org/problem?id=3233
题目意思:给一个矩阵n*n的矩阵A和一个k,求一个式子 S = A + A2 + A3 + … + Ak。
这个需要用到等比数列和的二分加速。
当n为奇数的时候,Sn=Sn-1+A^k;
当n为偶数的时候,Sn=(S[n/2]+E)*A^(k/2)
自己xjb推一下就知道等比数列和的二分加速是咋回事了。我举个例子,我们假设求等比数列2,4,8,16,32,64的和s=(8+1)*(2+4+8),而2+4+8=(2+4)+8,而(2+4)=(2+1)*2,其他的可以一次类推。
这个过程我们可以直接用一个递归过程算出来,其余我们套用矩阵快速幂的模板就好了。
代码:
1 //Author: xiaowuga 2 #include<iostream> 3 #include<cstring> 4 #define maxx INT_MAX 5 #define minn INT_MIN 6 #define inf 0x3f3f3f3f 7 #define size 35 8 using namespace std; 9 typedef long long ll; 10 int n,k,mod; 11 struct Mat{ 12 int mat[size][size]; 13 void clear(){ 14 memset(mat,0,sizeof(mat)); 15 } 16 17 Mat operator *(const Mat &e) const{ 18 Mat tmp; 19 tmp.clear(); 20 for(int k=0;k<n;k++) 21 for(int i=0;i<n;i++){ 22 if(mat[i][k]==0) continue; 23 for(int j=0;j<n;j++){ 24 if(e.mat[k][j]==0) continue; 25 tmp.mat[i][j]+=mat[i][k]*e.mat[k][j]%mod; 26 tmp.mat[i][j]%=mod; 27 } 28 } 29 return tmp; 30 } 31 Mat operator +(const Mat &e) const{ 32 Mat tmp; 33 tmp.clear(); 34 for(int i=0;i<n;i++){ 35 for(int j=0;j<n;j++){ 36 tmp.mat[i][j]=(mat[i][j]%mod+e.mat[i][j]%mod)%mod; 37 } 38 } 39 return tmp; 40 } 41 }; 42 Mat m,E; 43 Mat pow(Mat ma,ll num){ 44 Mat ans; 45 ans.clear(); 46 for(int i=0;i<n;i++) ans.mat[i][i]=1; 47 while(num){ 48 if(num&1) ans=ans*ma; 49 num/=2; 50 ma=ma*ma; 51 } 52 return ans; 53 } 54 Mat fun(int x){ 55 if(x==1) return m; 56 if(x&1) return fun(x-1)+pow(m,x); 57 else return (pow(m,x/2)+E)*fun(x/2); 58 } 59 int main() { 60 ios::sync_with_stdio(false);cin.tie(0); 61 cin>>n>>k>>mod; 62 E.clear(); 63 for(int i=0;i<n;i++) E.mat[i][i]=1; 64 for(int i=0;i<n;i++) 65 for(int j=0;j<n;j++) cin>>m.mat[i][j]; 66 Mat ans=fun(k); 67 for(int i=0;i<n;i++){ 68 for(int j=0;j<n;j++) 69 cout<<ans.mat[i][j]<<" "; 70 cout<<endl; 71 } 72 return 0; 73 }
时间: 2024-10-06 04:55:17