J-Sequence HDU-6395(行列の高速パワー+類推のアイデア(ここで初めて線形代数行列演算を適用する(まだ非常に満足)))

ここに画像の説明を挿入
ここに画像の説明を挿入
この問題は、単純なフィボナッチ数列の高速べき乗だけではありません。断片的な考え方もあります(ここでは数論も使用されます):
この問題解決するには、最初に行列の高速べき乗を明確にする必要があると思います。行列の高速累乗は、私たちが通常書く指数の高速累乗と同じです(類似の考え方)。
まず、最も単純な行列の高速累乗について説明し
ましょう構造知識またはクラス知識を使用して記述できます。
これが構造体バージョンです(最も単純なフィボナッチ数列計算を解きます):
ここに画像の説明を挿入
次に:
計算(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;
}

おすすめ

転載: blog.csdn.net/qq_44555205/article/details/97970000