二进制的思想。解题直接套模板了。主要是如何构造矩阵。
有个思想是把矩阵转换成路径方案数,有点像状态转移的样子,画几个点代表各种状态,然后之间的有向边代表与某值相乘的操作,实现所有状态的转移。
至于矩阵,比如从点1转移到点2,a[1][2]就代表从1状态转移到2状态,值为1→2边的值。
题意:给出n×n的矩阵A,正整数k。
求S=A+A2+A3+…+Ak.
思路:S[k]=S[k-1]+A^k
点1初始值为E,点2初始值为A,
那转移一次点1还是E,点2就是A+A^2。
a[1][1]=E, a[1][2]=A;
a[2][1]=O, a[2][2]=A;
注意NUM的大小,为此RE了好久。。
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int NUM=65;
int maxn,mod,n;
struct Matrix{
int a[NUM][NUM];
Matrix(){
memset(a, 0, sizeof a);
}
void Init(){
for(int i=0; i<maxn; i++)
for(int j=0; j<maxn; j++)
a[i][j] = (i == j);
}
Matrix operator + (const Matrix & B) const{
Matrix C;
for(int i=0; i<maxn; i++)
for(int j=0; j<maxn; j++)
C.a[i][j] = (a[i][j] + B.a[i][j])%mod;
return C;
}
Matrix operator * (const Matrix & B) const{
Matrix C;
for(int i=0; i<maxn; i++)
for(int j=0; j<maxn; j++){
C.a[i][j] = 0;
for(int k=0; k<maxn; k++){
C.a[i][j] = (C.a[i][j] + (1LL*a[i][k] * B.a[k][j])%mod)%mod;
}
}
return C;
}
Matrix operator ^ (const int &t)const{
Matrix A = (*this), res;
res.Init();
int p = t;
while(p){
if(p & 1) res = res * A;
A = A * A;
p >>= 1;
}
return res;
}
};
void output(Matrix a)//输出矩阵
{
for(int i=0;i<n;i++)
for(int j=n;j<maxn;j++)
printf("%d%c",a.a[i][j],j==maxn-1?'\n':' ');
}
int main()
{
int k;
while(~scanf("%d%d%d",&n,&k,&mod)){
maxn=2*n;
Matrix A;
A.Init();
for(int i=0;i<n;i++)
for(int j=n;j<maxn;j++){
scanf("%d",&A.a[i][j]);
A.a[i+n][j]=A.a[i][j];
}
Matrix ans;
ans=A^k;
output(ans);
}
return 0;
}