题目描述:
点击打开链接
一道标准的模版化的矩阵快速幂,简单说一下矩阵快速幂,矩阵快速幂主要是用于加速递推式的计算,举个例子,斐波那契数列fib[n]=fib[n-1]+fib[n-2],第n项需要用到后面两项,那么先构造一个2行的矩阵(1)。
我们还需要一个2*2的矩阵,希望这两个矩阵相乘能够算出fib[n]的结果,同时要保证我算出来的矩阵能够继续递推fib[n+1]的答案,所以算出的矩阵的第二行应该为fib[n-1],那么接下来根据各项系数我们可以很容易的构造出这个矩阵(2)如下
这时我们可以发现我们用初始矩阵不断去和这个矩阵进行矩阵乘法,就可以递推出fib[n],fib[n+1],fib[n+2]....的值,那么我们可以将初始矩阵(3)设为
那么我要计算fib[n]的值,只需要将这个矩阵去和矩阵(2)进行n-2次矩阵相乘就行了,所以此时就是要算矩阵(2)的n-2次幂,高次幂的写法模仿快速幂去写就行了
最后回到这题,用如上方法就可以很容易的构造出我们需要的矩阵
3 | 2 | 7 | 0 |
1 | 0 | 0 | 0 |
0 | 1 | 0 | 0 |
3 | 2 | 7 | 1 |
结果就是矩阵(1)*矩阵(2)^(n-2)的最后一行
AC代码:
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<string>
#include<stack>
#include<queue>
#include<vector>
#include<algorithm>
using namespace std;
const int MOD=2009;
struct MAT
{
long long s[4][4];
MAT ()
{
memset(s,0,sizeof(s));
}
void init()
{
s[0][0]=3;s[0][1]=2;s[0][2]=7;s[0][3]=0;
s[1][0]=1;s[1][1]=0;s[1][2]=0;s[1][3]=0;
s[2][0]=0;s[2][1]=1;s[2][2]=0;s[2][3]=0;
s[3][0]=3;s[3][1]=2;s[3][2]=7;s[3][3]=1;
}
};
long long n;
MAT MAT_MUL(MAT &m1,MAT &m2)
{
MAT m3;
for (int i=0;i<4;i++)
{
for (int j=0;j<4;j++)
{
for (int k=0;k<4;k++)
m3.s[i][j]=(m3.s[i][j]+m1.s[i][k]*m2.s[k][j])%MOD;
}
}
return m3;
}
MAT MAT_POW(MAT m1,MAT m2,int x)
{
while(x)
{
if (x&1) m2=MAT_MUL(m1,m2);
m1=MAT_MUL(m1,m1);
x=x>>1LL;
}
return m2;
}
int main()
{
int T;
scanf("%d",&T);
int cas=1;
while(T--)
{
scanf("%lld",&n);
if (n==0) {printf("Case %d: 1\n",cas); cas++; continue;}
if (n==1) {printf("Case %d: 4\n",cas); cas++; continue;}
if (n==2) {printf("Case %d: 9\n",cas); cas++; continue;}
MAT m1;
m1.init();
MAT m2;
for (int i=0;i<4;i++)
for (int j=0;j<4;j++)
if (i==j) m2.s[i][j]=1;
MAT m3=MAT_POW(m1,m2,n-2);
long long ans=0;
ans=(ans+5*m3.s[3][0])%MOD;
ans=(ans+3*m3.s[3][1])%MOD;
ans=(ans+1*m3.s[3][2])%MOD;
ans=(ans+9*m3.s[3][3])%MOD;
printf("Case %d: %lld\n",cas,ans);
cas++;
}
return 0;
}