题目大意:给定一个 n∗n 的矩阵 A ,求 Ak mod 1000000007
n≤50,k≤210000
首先先介绍一下特征值的相关内容……
对于矩阵 A ,若存在常数 λ 以及非零列向量 x ,使得 Ax=λx ,则称 λ 为矩阵 A 的一个特征值, x 为矩阵 A 的一个特征向量。
Ax=λx
Ax=λIx
(A−λI)x=0
|A−λI|=0
∣∣∣∣∣∣A11−λA21⋮An1A12A22−λ⋮An2⋯⋯⋯A1nA2n⋮Ann−λ∣∣∣∣∣∣=0
设 A 的特征多项式 f(λ)=|A−λI| 为关于 λ 的 n 次多项式,则 f(λ) 的 n 个零点即为 A 的 n 个特征值。
如何求特征多项式?
拉格朗日插值法,分别带入 λ=x0,x1,...,xn ,求行列式得到 y0,y1,...,yn ,则 f(x)=∑ni=0∏j≠i(x−xj)(xi−xj)yi ,时间复杂度 O(n4)
特征多项式有啥用?
Cayley-Hamilton定理: f(A)=0
故有 Ak=Ak mod f(A)
xk mod f(x) 是一个 n−1 次多项式,快速幂求出,然后代入矩阵 A 即可。
总时间复杂度 O(n4+n2logk)
#include
#include
#include
#include
#define M 55
#define MOD 1000000007
using namespace std;
char s[10100];
int n;
int a[M][M],b[M][M],ans[M][M];
int y[M];
long long Quick_Power(long long x,int y)
{
long long re=1;
while(y)
{
if(y&1) (re*=x)%=MOD;
(x*=x)%=MOD; y>>=1;
}
return re;
}
int Det(int a[M][M])
{
int k;
long long re=1;
for(int i=1;i<=n;i++)
{
for(k=i;k<=n;k++)
if(a[k][i])
break;
if(k==n+1)
return 0;
if(k!=i)
{
(re*=MOD-1)%=MOD;
for(int j=1;j<=n;j++)
swap(a[i][j],a[k][j]);
}
(re*=a[i][i])%=MOD;
long long temp=Quick_Power(a[i][i],MOD-2);
for(int j=1;j<=n;j++)
a[i][j]=a[i][j]*temp%MOD;
for(k=1;k<=n;k++)
if(k!=i)
{
long long temp=(MOD-a[k][i])%MOD;
for(int j=1;j<=n;j++)
(a[k][j]+=a[i][j]*temp%MOD)%=MOD;
}
}
return re;
}
struct Polynomial{
int a[M<<1];
Polynomial(int x)
{
memset(a,0,sizeof a);
a[0]=x;
}
int& operator [] (int x)
{
return a[x];
}
friend Polynomial operator + (Polynomial x,Polynomial y)
{
Polynomial z(0);
for(int i=0;i<=n<<1;i++)
z[i]=(x[i]+y[i])%MOD;
return z;
}
friend Polynomial operator * (Polynomial x,Polynomial y)
{
Polynomial z(0);
for(int i=0;i<=n;i++)
for(int j=0;j<=n;j++)
(z[i+j]+=(long long)x[i]*y[j]%MOD)%=MOD;
return z;
}
Polynomial operator * (long long x)//f(x)*a;
{
Polynomial re(0);
for(int i=0;i<=n<<1;i++)
re[i]=(a[i]*x)%MOD;
return re;
}
Polynomial Times(long long x,long long y) //f(x)*(ax+b)
{
Polynomial re(a[0]*y%MOD);
for(int i=1;i<=n<<1;i++)
re[i]=(a[i-1]*x+a[i]*y)%MOD;
return re;
}
friend Polynomial operator % (Polynomial a,Polynomial b) // a%b
{
for(int i=n;~i;i--)
{
long long temp=(MOD-a[i+n]*Quick_Power(b[n],MOD-2)%MOD)%MOD;
for(int j=0;j<=n;j++)
(a[i+j]+=b[j]*temp%MOD)%=MOD;
}
return a;
}
};
int main()
{
scanf("%s",s);
cin>>n;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
scanf("%d",&a[i][j]);
for(int x=0;x<=n;x++)
{
memcpy(b,a,sizeof a);
for(int i=1;i<=n;i++)
(b[i][i]+=MOD-x)%=MOD;
y[x]=Det(b);
}
Polynomial p(0);
for(int x=0;x<=n;x++)
{
Polynomial temp(1);
for(int i=0;i<=n;i++)
if(i!=x)
{
temp=temp.Times(1,MOD-i);
temp=temp*Quick_Power((x-i+MOD)%MOD,MOD-2);
}
temp=temp*y[x];
p=p+temp;
}
Polynomial x(0);x[1]=1;
Polynomial re(1);
for(int i=strlen(s)-1;~i;i--)
{
if(s[i]=='1')
re=re*x%p;
x=x*x%p;
}
memset(b,0,sizeof b);
for(int i=1;i<=n;i++)
b[i][i]=1;
for(int k=0;kfor(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
(ans[i][j]+=(long long)b[i][j]*re[k]%MOD)%=MOD;
static int c[M][M];
memset(c,0,sizeof c);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
for(int k=1;k<=n;k++)
(c[i][j]+=(long long)a[i][k]*b[k][j]%MOD)%=MOD;
memcpy(b,c,sizeof b);
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
printf("%d%c",ans[i][j],j==n?'\n':' ');
return 0;
}