給定一個矩陣,求其前k次方的矩陣和。
二分+矩陣快速冪,S=(A1+A2+…+An)+(A1+A2+…+An)*k,然後遞歸求解A1+A2+…+An,遞歸結束條件k==1。
很早以前看的這題,當時不會,拖啊拖的,今天靈光乍現,不過A的也不順利,遞歸一直寫錯,最後才AC。
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
typedef struct D {
int A[35][35];
}D;
D dd,kk;
int n,m;
D multi(D a,D b){
D t;
memset(t.A,0,sizeof(t.A));
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
for(int k=0;k<n;k++){
t.A[i][j]+=a.A[i][k]*b.A[k][j];
t.A[i][j]%=m;
}
}
}
return t;
}
D add(D a,D b){
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
a.A[i][j]+=b.A[i][j];
a.A[i][j]%=m;
}
}
return a;
}
D pow(int k){
D p=dd,ans;
memset(ans.A,0,sizeof(ans.A));
for(int i=0;i<n;i++){
ans.A[i][i]=1;
}
while(k>0){
if(k&1){
ans=multi(ans,p);
}
p=multi(p,p);
k>>=1;
}
return ans;
}
D calcu(int k){
if(k==1) return dd;
D t=calcu(k>>1);
if(k&1){
D tt=pow((k>>1)+1);
return add(add(t,tt),multi(t,tt));
}
else {
D tt=pow(k>>1);
return add(t,multi(t,tt));
}
}
int main(){
//freopen("in.txt","r",stdin);
int k;
cin>>n>>k>>m;
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
cin>>dd.A[i][j];
kk.A[i][j]=dd.A[i][j];
}
}
D ss=calcu(k);
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
printf("%d%s",ss.A[i][j],(j+1>=n)?"\n":" ");
}
}
return 0;
}
注:
不過題目的數據有點弱,有一個數據有明顯的錯誤,這個代碼還是AC了。此處註明,日後再解。
數據:
10 10000 100000
2 1 1 1 1 1 1 1 1 1
1 4 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 9 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1