矩阵快速幂是通过一个状态去求出他下一个状态;
矩阵乘法的基础知识:
矩阵快速幂主要涉及的知识点: 乘法结合律: (AB)C=A(BC).
矩阵的乘法规则:
矩阵快速幂的模板(我自己常用的):
struct Matrix
{
int M[N][N];
}A;
Matrix Mul(Matrix a,Matrix b,int NN)
{//矩阵相乘
int i,j,k;
Matrix c;
for(i = 0; i < NN; i++)
for(j = 0; j < NN; j++)
{
c.M[i][j] = 0;
for(k = 0; k < NN; k++)
c.M[i][j] += a.M[i][k]*b.M[k][j];
}
return c;
}
Matrix pow(int t,int NN)
{//快速幂
Matrix res,a = A;
memset(res.M,0,sizeof res.M);
for(int i = 0; i < NN; i++)
res.M[i][i] = 1; //单位矩阵
while(t)
{
if(t&1)
res = Mul(res,a,NN);
a = Mul(a,a,NN);
t>>=1;
}
return res;
}
矩阵相乘时复杂度主要是在进行矩阵连乘,其复杂度为O(n^3),所以在构造矩阵是一定要注意n的取值范围;
话不多说,直接切题!
构造矩阵是至关重要的!
1.poj 3070 斐波拉契
我们都知道斐波拉契的推导式:F[n] = F[n-1]+F[n-2] (n>2);F[1] = 1,F[2] = 2;
由这个推导公式我们可以构造一个A(2*2)矩阵,一个目标矩阵,通过计算A^n(次数要自己去计算)次就可以得出F[n]。
//套上模板即可
int main()
{
long long n,cnt = 0;
while(~scanf("%lld",&n)&&n!=-1)
{
Matrix A;
cnt = 0;
A.M[0][0]=0;A.M[0][1]=1;
A.M[1][0]=1;A.M[1][1]=0;
F[0] = 1,F[1] = 1;
Matrix ans=pow_mod(A,n);
cnt += F[0]*A.M[0][0]+F[1]*A.M[0][1];
}
return 0;
}
2.KiKi & Little Kiki2 hdu_2276
题意:给你一个环形灯 ,如果他左边的灯是开着的就在下一秒关掉该灯或者打开,问n秒后灯的状态,这样可以知道,由上一个状态去推下个状态;可以判断出该灯下一秒的状态只与它左边的一个灯相关,这样我们构造矩阵时只需够造它左边的数值以及本身,其余为0;
然后相加模2即可;
int main()
{
while(scanf("%d",&n)==1)
{
memset(T,0,sizeof T);
memset(A.M,0,sizeof A.M);
cin>>s;
int len = strlen(s);
int cnt = 0;
for(int i = 0; i < len; i++)
T[cnt++] = s[i]-'0';
for(int i = 0; i < cnt-1; i++)
A.M[i][i] =A.M[i+1][i]= 1;
A.M[cnt-1][cnt-1] = A.M[0][cnt-1]=1;
A = pow(n,cnt);
for(int i = 0; i < cnt; i++)
{
int ans = 0;
for(int j = 0; j < cnt; j++)
ans+=A.M[i][j]*T[j];
printf("%d",ans%2);
}
cout<<endl;
}
return 0;
}
3.hdu 5015 23333 Matrix
每次变化的都有233没次乘10加上3;
a 0,1 = 233,a 0,2 = 2333,a 0,3 = 23333...
ai,j = a i-1,j +a i,j-1( i,j ≠ 0). Now you have known a 1,0,a 2,0,...,a n,0,
我们应该构造
233 10 0 0 0 1 23
x1+233 10 1 0 0 1 x1
x1+x2+233 = 10 1 1 0 1 * x2
x1+x2+x3+233 10 1 1 1 1 x3
3 0 0 0 0 0 3
因而
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
memset(A,0,sizeof A);
memset(C.M,0,sizeof C.M);
for(int i = 1; i <= n; i++)
scanf("%lld",&A[i]);
A[0] = 23;
A[n+1] = 3;
for(int i = 0; i < n+1; i++)
{
C.M[i][0] = 10;
C.M[i][n+1] = 1;
}
C.M[n+1][n+1] = 1;
for(int i = 1; i < n+1; i ++)
for(int j = 1; j <= i; j++)
C.M[i][j] = 1;
C = pow(m);
ll ans = 0;
for(int i = 0; i < n+2; i++)
ans = (ans+C.M[n][i]*A[i]%mod)%mod;
cout<<ans<<endl;
}
return 0;
}
还有一些题目,由于时间关系,我之后整理上去!