在作者的上一篇博客中,我们提到了矩阵加速的另一道题
这次,我们来看一道LGOJ上的板题:P1939
一句话题意::,求
这道题是一道非常简单的矩阵加速题,可以用来练练手
我们可以很轻松的想到原数组:
也就是
那么我们要构造一个的加速矩阵
首先,直接可以变成
所以加速矩阵的第一列就是
然后,也可以直接由原数组得到
所以加速矩阵的第二列就是
最后,变到
需要他本身再加上
所以最后一列就是
综上::
这就是这道题的基本结构
还要注意几个细节
- 无限输入
- 换行
- 乘
次
自此我们可以给出代码::
#include<cstdio>
#include<cstring>
inline void read(long long &x) {
x=0;
long long f=1;
char s=getchar();
while(s<'0'||s>'9') {
if(s=='-')
f=-1;
s=getchar();
}
while(s>='0'&&s<='9') {
x=x*10+s-48;
s=getchar();
}
x*=f;
}
inline void pr(long long x) {
if(x<0) {
putchar('-');
x=-x;
}
if(x>9)
pr(x/10);
putchar(x%10+48);
}//快读快输不解释
long long A[3][3]= {{0,0,1},{1,0,0},{0,1,1}},n,m,ans[3]= {1,1,1},s[3];//构建加速矩阵、初始矩阵、答案矩阵
inline void cheng(long long a[3][3],long long b[3][3]) {//矩阵乘法运算
long long c[3][3];
memset(c,0,sizeof(c));//初始化
for(long long i=0; i<3; i++)
for(long long j=0; j<3; j++)
for(long long k=0; k<3; k++)
c[i][j]=(c[i][j]+a[i][k]%m*b[k][j]%m)%m;//矩阵乘法
memcpy(a,c,sizeof(c));//传答案
}
inline void ksm(long long a[3][3],long long k) {//模拟快速幂
if(k==1) {//只有一次
memcpy(a,A,sizeof(A));//直接传
return;
}
long long c[3][3];
ksm(c,k/2);//除以二
cheng(c,c);//平方
if(k&1)//k为奇数
cheng(c,A);
memcpy(a,c,sizeof(c));//传答案
}
long long T;
int main() {
read(T);
m=1000000007;
while(T--) {
read(n);
if(n==1||n==2)//特殊判断
putchar(49),putchar('\n');//注意换行
else {
ksm(A,n-1);//加速
for(long long j=0; j<3; j++)
for(long long k=0; k<3; k++)
s[j]=(s[j]+ans[k]%m*A[k][j]%m)%m;//最后还要再乘一次
pr(s[0]),putchar('\n');
}
A[0][0]=A[0][1]=A[1][1]=A[1][2]=A[2][0]=s[0]=s[1]=s[2]=0;
A[0][2]=A[1][0]=A[2][1]=A[2][2]=ans[1]=ans[2]=ans[3]=1;//无限输入注意清零
}
}
这就是这道题的全部代码
有错误的欢迎指出