这道题不仅仅是简单的斐波那契数列矩阵快速幂了;还有分段思想(这里还用到了数论):
解决这道题,我觉得应该先把矩阵快速幂搞得清清楚楚才行,其实矩阵快速幂和一般我们写的指数的快速幂是一个道理(类比思想);
首先说最简单的矩阵快速幂吧:
我们可以利用结构体知识或者class知识都可以写;
这里给出结构体版本(解决最简单的斐波那契数列的计算):
那么:
对于计算(第n项的值)斐波那契数列就很easy了(这里是取了Mod的,不然会越界):
#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define Mod 100000007
typedef long long ll;
#define N 2//这里表示2*2的矩阵//如果是3*3的 则可以令为N 3
struct Mu{
ll a[N][N];
Mu(){
memset(a,0,sizeof(a));
}
};
Mu Multiply(Mu t1,Mu t2){//求两个矩阵相乘
Mu res;
for(ll i=0;i<N;i++){
for(ll j=0;j<N;j++){
for(ll k=0;k<N;k++)
{
res.a[i][j]=(res.a[i][j]+t1.a[i][k]*t2.a[k][j])%Mod;
}
}
}
return res;
}
Mu QP(Mu x,ll n)//矩阵快速幂 返回结果对象
{
Mu res;
res.a[0][0]=res.a[1][1]=res.a[2][2]=1;//单位矩阵
while(n){
if(n&1){
res=Multiply(res,x);
}
x=Multiply(x,x);
n>>=1;
}
return res;
}
Mu ans;
ll n,F1=1,F2=1;
void init(){
//初始化矩阵
//比如斐波那契数列
ans.a[0][0]=ans.a[0][1]=ans.a[1][0]=1;
}
void Ans(){
ans=QP(ans,n-2);//算ans^n
cout<<(ans.a[0][0]*F1+ans.a[0][1]*F2)%Mod<<endl;
}
int main(){
cin>>n;
if(n==1) return cout<<F1<<endl,0;
else if(n==2) return cout<<F2<<endl,0;
init();
Ans();
return 0;
}
是不是很强大,嘻嘻;但是解决这道题还远远不够;
这道题第一点就是递推公式不好找,二点就是分段问题是个难点(因为平常分会超时),解决了这两点就可以AC这道题了;
直接看代码吧(主要是对自定义类传递参数和Java里面不同,我现在能够分的很清楚了!!嘻嘻);
递推公式:
所以由于矩阵乘法结合律所以这里从往左算;
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define Mod 1000000007
struct Mu{
ll a[3][3];//就是这里我WA了很多次,没有写ll结果自己Debug了半天 我还以为自己把快速幂写错了,太无语了
Mu(){//构造函数
memset(a,0,sizeof(a));
}
};
Mu mu(Mu t1,Mu t2){
Mu res;
for(ll i=0;i<3;i++){
for(ll j=0;j<3;j++){
for(ll k=0;k<3;k++){
res.a[i][j]=(res.a[i][j]+t1.a[i][k]*t2.a[k][j])%Mod;
}
}
}
return res;
}
Mu QP(Mu x,int n){
Mu res;
res.a[0][0]=res.a[1][1]=res.a[2][2]=1;
while(n){
if(n&1){
res=mu(res,x);
}
x=mu(x,x);
n>>=1;
}
return res;
}
//int Period(int P,int i){
// int j;
//
// for(j=i;(P/i)==(P/j);j++);
// return j;
//}
int main(){
ll T,A,B,C,D,P,n;
scanf("%lld",&T);
while(T--){
scanf("%lld %lld %lld %lld %lld %lld",&A,&B,&C,&D,&P,&n);
if(n==1) {printf("%lld\n",A);continue;}
if(n==2) {printf("%lld\n",B);continue;}
ll j;
Mu s,ans;
for(int i=3;i<=n;i=j+1){
//memset(s.a,0,sizeof(s.a));//因为每次都需要置为0
s.a[0][0]=D;s.a[0][1]=C;s.a[0][2]=P/i;
s.a[1][0]=1;
s.a[2][2]=1;
//算阶段幂
if(i>P){//这里是算最后一次
ans=QP(s,n-i+1);
B=(ans.a[0][0]*B%Mod+ans.a[0][1]*A%Mod+ans.a[0][2])%Mod;
break;
}
j=min(n,P/(P/i));//这里必须要比最小值,用如果大于了n就不成立了
ans=QP(s,j-i+1);
ll t1=(ans.a[0][0]*B+ans.a[0][1]*A+ans.a[0][2])%Mod;//这里就是为什么需要更新A,B,因为由上面图的分析可以知道
ll t2=(ans.a[1][0]*B+ans.a[1][1]*A+ans.a[1][2])%Mod;
B=t1;A=t2;//因为这里的矩阵是倒起来算的,所以需要每次更新A,B
}
printf("%lld\n",B);//最后输出B
}
return 0;
}