矩阵——P1962 斐波那契数列
https://www.luogu.org/problem/show?pid=1962
嗯……………………
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#define Ll long long
using namespace std;
struct jv{
int n,m;
Ll a[3][3];
jv(){n=m=0;memset(a,0,sizeof a);}
}a,ans,c;
Ll n,mo=1000000007;
jv cheng(jv a,jv b){
jv ans; ans.n=a.n; ans.m=b.m;
for(int i=1;i<=a.n;i++)
for(int k=1;k<=a.m;k++)if(a.a[i][k])
for(int j=1;j<=b.m;j++)
ans.a[i][j]=(ans.a[i][j]+a.a[i][k]*b.a[k][j])%mo;
return ans;
}
int main()
{
scanf("%lld",&n);
if(n<3){printf("1");return 0;}
n-=3;
a.n=a.m=2;
a.a[1][1]=a.a[1][2]=a.a[2][1]=1;
ans=a;
while(n){
if(n&1)ans=cheng(ans,a);
n>>=1;
a=cheng(a,a);
}
c.n=2; c.m=1;
c.a[1][1]=c.a[2][1]=1;
ans=cheng(ans,c);
printf("%lld",ans.a[1][1]);
}
首先我们定义一个struct
struct jv{
int n,m;
Ll a[3][3];
jv(){n=m=0;memset(a,0,sizeof a);}
};
更新矩阵的时候千万不要把n,m漏掉;
那么我们咋么矩乘呢;
两个矩阵
第一个矩阵的列和第二个矩阵的行一定要相同;
所以我们可以把一个矩阵的列与第二个矩阵的行相乘合并,组成一个新的矩阵,新矩阵的行是第一个矩阵的行,列是第二个矩阵的列;
新矩阵的[1,1]是第一个矩阵的Σ[1,k]*[k,1] (k=1->n)
新矩阵的[1,2]是第一个矩阵的Σ[1,k]*[k,2] (k=1->n)
…..
新矩阵的[i,j]是第一个矩阵的Σ[i,k]*[k,j] (k=1->n)
所以说相乘代码
jv cheng(jv a,jv b){
jv ans; ans.n=a.n; ans.m=b.m;
for(int i=1;i<=a.n;i++)
for(int j=1;j<=b.m;j++)
for(int k=1;k<=a.m;k++)
ans.a[i][j]=(ans.a[i][j]+a.a[i][k]*b.a[k][j])%mo;
return ans;
}
这个就是模拟;
当然还是有优化的;
jv cheng(jv a,jv b){
jv ans; ans.n=a.n; ans.m=b.m;
for(int i=1;i<=a.n;i++)
for(int k=1;k<=a.m;k++)if(a.a[i][k])
for(int j=1;j<=b.m;j++)
ans.a[i][j]=(ans.a[i][j]+a.a[i][k]*b.a[k][j])%mo;
return ans;
}
这样更快,快到飞起;
关于斐波那契;
我们先搞一刁矩阵;
我们先考虑怎么跟新f[n-1],f[n-2]…
显然只要把f[n]给f[n-1],f[n-1]给f[n-2]就好了;
所以斐波那契的矩阵
自己模拟模拟把
那么对于f[n]
如果f[n]=f[n-1]-2*f[n-2]+6*f[n-3]
那么
想通的话显然得不行