数列变换题解
作者:互联网
题解
1.分析题目
1.矩阵乘法
如果想要\(AC\)这道题,就需要学习矩阵乘法。顾名思义,矩阵乘法就是矩阵乘矩阵的运算。
矩阵乘法的运算法则如下:
现有一个\(N \times P\)的矩阵\(A\)和一个\(P \times M\)的矩阵\(B\),令矩阵\(C=A\times B\),则\(C_{i,j}=\sum\limits_{k=1}^{P}A_{i,k}\times B_{k,j}\)。
如\(\begin{bmatrix}1&1&2 \\ 3&2&4\end{bmatrix} \times \begin{bmatrix}1\\3\\2\end{bmatrix}=\begin{bmatrix}1\times1+1\times3+2\times2 \\ 3\times1+2\times3+4\times2\end{bmatrix}=\begin{bmatrix}8\\17\end{bmatrix}\)
经典问题\(Fibonacci\)数列就可以用矩阵乘法解决。
我们需要一个基础矩阵\(A\),大小为\(1\times2\)。我们在矩阵中维护两个信息:数列中当前数的数值以及前一个数的数值。比如基础矩阵\(A=\begin{bmatrix}0&1\end{bmatrix}\),表示第一个数为一,通关计算得到第零个数为0。我们还需要一个常数矩阵\(B=\begin{bmatrix}0&1\\1&1\end{bmatrix}\),每次将\(A\)更新为\(A\times B\),就可以得到\(A\)的下一个状态。循环\(N\)次后,\(A_{1,2}\)即位\(Fib_N\)。
此时,我们通过观察\(A=A\times B\)这个式子,不难发现\(A\)其实只是乘上了\(B^N\),这让我们不禁又想起了快速幂这个好东西。
2.快速幂
如果想求\(a^x\)是多少,最粗暴的方式就是枚举,那有没有什么算法可以优化呢?
当然有!我们只需要将\(x\)进行二进制拆分,从低位到高位进行枚举。如果这位是一,每次将结果\(ans\)乘上\(a^{2^i}\)就可以了。
\(Code:\)
void Pow(long long a,int x){
long long tmp=a,ans=1ll;
for(;x;x>>=1){
if(x&1){
ans*=tmp;
}
tmp*=tmp;
}
}
用快速幂求\(Fibonacci\):
long long a[2]={0,1},b[2][2]={{0,1},{1,1}};
void mul_self(){
long long c[2][2]={{0,0},{0,0}};
for(int i=0;i<2;i++){
for(int j=0;j<2;j++){
for(int k=0;k<2;k++){
c[i][j]+=b[i][k]*b[k][j];
}
}
}
}
void mul(){
long long c[2]={0,0};
for(int i=0;i<2;i++){
for(int j=0;j<2;j++){
c[i]+=a[j]*b[j][i];
}
}
}
void Pow(int n){
for(;n;n>>=1){
if(n&1)mul();
mul_self();
}
}
3.回归题目
回到题目,我们可以把这道题和\(Fibonacci\)数列题目类比起来,不难发现,基础矩阵\(A=\begin{bmatrix}x_1,x_2,\cdots,x_n\end{bmatrix}\),常数矩阵\(B=\begin{bmatrix}0&0&0&\cdots&a_1 \\ 1&0&0&\cdots&a_2\\0&1&0&\cdots&a_3\\\vdots&\vdots&\vdots&\ddots&\vdots\\0&0&0&\cdots&a_n\end{bmatrix}\),将这两个矩阵按照上面的方法进行操作即可
代码
\(Code:\)
#include<bits/stdc++.h>
#include<cstdio>
using namespace std;
const long long M=998244353;
int n;
long long m,a[105],x[105];
long long matrix[105][105];
void fast(){
for(;m;m>>=1){
if(m&1){
long long X[105];
memset(X,0,sizeof(X));
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
X[i]+=x[j]*matrix[j][i];
X[i]%=M;
}
}
memcpy(x,X,sizeof(X));
}
long long Matrix[105][105];
memset(Matrix,0,sizeof(Matrix));
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
for(int k=1;k<=n;k++){
Matrix[i][j]+=matrix[i][k]*matrix[k][j];
Matrix[i][j]%=M;
}
}
}
memcpy(matrix,Matrix,sizeof(Matrix));
}
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>a[i],a[i]%=M;
for(int i=1;i<=n;i++)cin>>x[i],x[i]%=M;
for(int i=1;i<n;i++)matrix[i+1][i]=1;
for(int i=1;i<=n;i++)matrix[i][n]=a[i];
m-=n;
fast();
cout<<x[n];
}
/*
C[1][j]=A[1][i]*B[i][j]
*/
标签:begin,end,数列,变换,题解,矩阵,long,times,bmatrix 来源: https://www.cnblogs.com/easonhe/p/16528257.html