この問題は、単純なフィボナッチ数列の高速べき乗だけではありません。断片的な考え方もあります(ここでは数論も使用されます):
この問題を解決するには、最初に行列の高速べき乗を明確にする必要があると思います。行列の高速累乗は、私たちが通常書く指数の高速累乗と同じです(類似の考え方)。
まず、最も単純な行列の高速累乗について説明し
ましょう。構造知識またはクラス知識を使用して記述できます。
これが構造体バージョンです(最も単純なフィボナッチ数列計算を解きます):
次に:
計算(n番目の項の値)フィボナッチ数列は非常に簡単です(ここで使用される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;
}
非常に強力ですか?しかし、この問題を解決するには十分と
は言えません。この問題の最初のポイントは、漸化式を見つけるのが簡単ではないということです。2番目のポイントは、セグメンテーションの問題が難しいポイントであるということです(通常のブランチタイムアウト)、これを解決するAC問題は2つのポイントで解決できます。
コードを見るだけです(主にカスタムクラスに渡されるパラメーターがJavaのパラメーターと異なるため、今では非常に明確に区別できます!! Hehe );
漸化式:
行列の乗算のため、結合法則は左から数えられます。
#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;
}