思路:看k的范围显然不能直接遍历来加,留意到S有一个性质
当k为偶数的时候 Sk = A+A^2+....A^(K/2)+A^(K/2)*(A+A^2+....A^(k/2))
当k为奇数的时候 Sk = A+A^2+....A^(K/2)+A^((K+1)/2) + A^((K+1)/2)*(A+A^2....A^(K/2))
显然符合递归性质,那么就可以二分地来求这个和了,求和的时候就从O(k)变为了O(log(k))
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n,mod;
struct Mat
{
int a[31][31]; //矩阵大小
}p;
Mat mul(Mat a,Mat b)
{
Mat t;
memset(t.a,0,sizeof(t.a));
for(int i = 0;i<n;i++)
{
for(int k = 0;k<n;k++)
{
if(a.a[i][k])
for(int j = 0;j<n;j++)
{
t.a[i][j]+=a.a[i][k]*b.a[k][j];
if(t.a[i][j]>=mod)
t.a[i][j]%=mod;
}
}
}
return t;
}
Mat expo(Mat p,int k)
{
if(k==1)return p;
Mat e;
memset(e.a,0,sizeof(e.a));
for(int i = 0;i<n;i++) //初始化单位矩阵
e.a[i][i]=1;
if(k==0)return e;
while(k)
{
if(k&1)
e = mul(p,e);
p = mul(p,p);
k>>=1;
}
return e;
}
Mat add(Mat a,Mat b)
{
Mat t;
memset(t.a,0,sizeof(t.a));
for(int i = 0;i<n;i++)
for(int j = 0;j<n;j++)
t.a[i][j]=(a.a[i][j]+b.a[i][j])%mod;
return t;
}
Mat sum(int k)
{
if(k==1)
return p;
if(k&1)
return add(sum(k-1),expo(p,k));
else
{
Mat tmp = expo(p,k/2);
Mat temp = sum(k/2);
return add(temp,mul(tmp,temp));
}
}
int main()
{
int k;
scanf("%d%d%d",&n,&k,&mod);
for(int i = 0;i<n;i++)
for(int j = 0;j<n;j++)
scanf("%d",&p.a[i][j]);
Mat ans;
memset(ans.a,0,sizeof(ans.a));
ans = sum(k);
for(int i = 0;i<n;i++,printf("\n"))
for(int j = 0;j<n;j++)
printf("%d ",ans.a[i][j]);
}