这个题,一开始就没想到竟然可以拿子矩阵的样子进行呈现,作为一个曾经数学系的孩子来说真的是还惭愧了。还搞了半天了。唉,这个题的看到还有递归的写法,先说说正常的快速幂的写法,这里在网上看到两种矩阵的递推式子
这个是第一种推导方法也就是我的做法,只需要最后在右上角的矩阵再减去一个E就可以饿。其间的可以用快速幂来求解。
然后就是第二种推导方法
这是第二种推导方法,也是可见明显可以得出答案的。
然后就是第二种递归的写法了,这个没怎么想到
同样这个递归也是很好写的,难的就是这个递推的式子不好搞定,想不出来就没法做了。
还有前面的两种矩阵的方式写法,实际上也是难在了矩阵的构造上了,如果构造出来,还是好解决的。
这里可以的出一点经验的就是其实一般的都是一个数的k次幂,然后我们借用矩阵幂来构造矩阵优化解决,当需要求的是矩阵的时候,实际上可以把矩阵看成一个数字,然后构造矩阵的矩阵来解决问题,也就是把原来矩阵看成构造后的子矩阵的方式来解决问题。
那么实际上如果是这个问题:
•eg.求S(n)=sigma(i^k)(n<10^9,k<100)
•结果对10^9+7取模
那么这个地方也就是要构造一个矩阵就可以,如下所示:
最后贴上代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
int n,k,m;
struct Mat
{
int mat[100][100];
};
Mat a;
Mat operator * (Mat a, Mat b) {
Mat mm;
memset(mm.mat, 0, sizeof(mm.mat));
int i, j, k;
for(i = 0; i < 2*n; ++i) {
// if(a.mat[i][k] <= 0) continue; //***
for(j = 0; j < 2*n; ++j) {
// if(b.mat[k][j] <= 0) continue; //***
for(k=0;k<2*n;++k)
{
mm.mat[i][j] =(mm.mat[i][j]+(a.mat[i][k] * b.mat[k][j])%m)%m;
}
}
}
return mm;
}
Mat operator ^ (Mat a, int k) {
Mat m,s;
memset(s.mat,0,sizeof(s.mat));
int i,j;
for(i = 0; i < 2*n; ++i)
for(j = 0; j < 2*n; ++j)
m.mat[i][j] = (i == j);
for( k++; k; k>>=1) {
if(k&1) m = m*a;
a=a*a;
}
return m;
}
int main()
{
while(scanf("%d%d%d",&n,&k,&m)==3)
{
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
scanf("%d",&a.mat[i][j]);
}
for(int i=0;i<n;i++)
{
a.mat[i+n][i+n]=a.mat[i][i+n]=1;
}
Mat sum=a^k;
for(int i=0;i<n;i++)
{
sum.mat[i][i+n]--;
}
for(int i=0;i<n;i++)
{
for(int j=n;j<2*n;j++)
{
if(j==n)
printf("%d",sum.mat[i][j]%m);
else
printf(" %d",sum.mat[i][j]%m);
}
puts("");
}
}
return 0;
}