題目鏈接:
題目描述:
給你5個數 :n,x,y,a,b(1<=n,x,y,z,b<=1e12)
f(1)=x,f(2)=y,f(i)=f(i-1)*f(i-2)*a^b(i>3)
讓你求f(n)%1e9+7的值
題解:
f(1)=x;
f(2)=y;
f(3)=x*y*a^b;
f(4)=x*y*a^b*y*a^b=x*y^2*a^2b
f(5)=x*y^2*a^2b*x*y*a^b*a^b=x^2*y^3*a^4b
f(6)=x^2*y^3*a^4b*x*y^2*a^2b=x^3*y^5*a^6b
設c爲常數
c x y
1 0 1 0
2 0 0 1
3 1 1 1
4 2 1 2
5 4 2 3
6 6 3 5
c:
i<3:fb2(1)=fb2(2)=0;
i>=3:fb2(i)=fb2(i-1)+fb2(i-1)+1;
//注意不能化成fb2(i)=fb2(i-1)*fb2(i-2)*a^b;
//因爲這樣不能用常量矩陣來維護,因爲矩陣乘法的每一項的結果是相加的。
ans1=a^(b*fb2(i)),相當於只維護冪次和
1 1 1 fb2(i-1) fb2(i)
1 0 0 * fb2(i-2) = fb2(i-1)
0 0 1 1 1
設t爲3*3的矩陣{{1,1,1},{1,0,0},{0,0,1}};
設ai爲3*1的矩陣{fb2(i),fb2(i-1),1}
則a1={fb2(2),fb2(1),1}
ai=a(i-1)*t
a2=a1*t
a3=a2*t=a1*t^2
=>ai=a1*t^(i-1)
=>
fb2(2) fb2(i)
t^(i-1) * fb2(1) = fb2(i-1)
1 1
如果要求fb2(n)
利用矩陣快速冪求出t^(n-1)
fb2(n)=t^(n-1)的第一行*a1的第一列(即矩陣{0,0,1})
則c對答案的貢獻爲 ans1=a^(b*fb2(n))(可以用快速冪求)x:
i<3:fb1(1)=1, fb1(2)=0;
i>=3:fb1(i)=fb1(i-1)+fb1(i-2);
1 1 fb1(i-1) fb1(i)
1 0 * fb1(i-2) = fb1(i-1)
設t爲2*2的矩陣{{1,1},{1,0}}
設ai爲2*1的矩陣{fb1(i),fb1(i-1)}
則a1爲2*1的矩陣{fb1(2),fb1(1)}
ai=a(i-1)*t;
a2=a1*t
a3=a2*t=a1*t*t=a1*t^2
a4=a3*t=a1*t*t*t=a*t^3;
根據遞推式可得
ai=a1*t^(i-1);
即
t^(i-1) fb1(2) fb1(i)
* fb1(1) = fb1(i-1).
故fb1(n)=t^(n-1)的第一行*a1(即矩陣{0,1})
因此對答案的貢獻是 ans2=x^fb1(n);
y:
i<3:fb1(1)=0,fb1(2)=1;
i>=3:fb1(i)=fb1(i-1)+fb1(i-2);
推導過程和上面類似,只不過初始值變了
可以自己再推一遍。
最後答案就是ans1*ans2%mod*ans3%mod
trick:
1.因爲x和y的遞推都是斐波那契數列,只不過初始值變了,而且x比y多了一位,所以我們可以放在一起考慮。
2.a^b對上面的指數取模時不能直接取,需要用到費馬小定理
定理內容:如果p是一個質數,而整數a不是p的倍數,則有a^(p-1)≡1(mod p)
3.根據上面的定理所以我們需要特判a是p的倍數的情況以及x,y是p的倍數的情況。
代碼實現:
#pragma GCC optimize(2) #include<iostream> #include<algorithm> #include<cmath> #include<cstring> #include<cstdio> #include<cstdlib> #include<vector> #include<map> #include<set> #include<stack> #include<queue> #define PI atan(1.0)*4 #define E 2.718281828 #define rp(i,s,t) for (register int i = (s); i <= (t); i++) #define RP(i,t,s) for (register int i = (t); i >= (s); i--) #define ll long long #define ull unsigned long long #define mst(a,b) memset(a,b,sizeof(a)) #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define pii pair<int,int> #define mp make_pair #define pb push_back using namespace std; inline int read() { int a=0,b=1; char c=getchar(); while(c<'0'||c>'9') { if(c=='-') b=-1; c=getchar(); } while(c>='0'&&c<='9') { a=(a<<3)+(a<<1)+c-'0'; c=getchar(); } return a*b; } ll n,x,y,a,b; const int INF = 0x3f3f3f3f; const ll mod = 1e9+7; struct matrix{ ll a[3][3]; }; matrix mul(matrix a,matrix b, ll m){ matrix res; rp(i,0,2) rp(j,0,2){ res.a[i][j]=0; rp(k,0,2){ res.a[i][j]=(res.a[i][j]+a.a[i][k]*b.a[k][j]%m)%m; } } return res; } matrix matrix_pow(matrix a,ll b,ll m){ matrix res; rp(i,0,2) rp(j,0,2) res.a[i][j]=0; res.a[1][1]=res.a[0][0]=res.a[2][2]=1; while(b){ if(b&1) res=mul(res,a,m); b>>=1; a=mul(a,a,m); } return res; } ll fb1(int flag,ll n,ll m){ matrix tmp; rp(i,0,2) rp(j,0,2) tmp.a[i][j]=0; tmp.a[0][0]=tmp.a[0][1]=tmp.a[1][0]=1; tmp=matrix_pow(tmp,n-1,m); if(flag==1) return tmp.a[0][1]%m; else return tmp.a[0][0]%m; } ll fb2(ll n,ll m){ matrix tmp; rp(i,0,2) rp(j,0,2) tmp.a[i][j]=0; tmp.a[0][0]=tmp.a[0][1]=tmp.a[0][2]=tmp.a[1][0]=tmp.a[2][2]=1; tmp=matrix_pow(tmp,n-1,m); return tmp.a[0][2]%m; } ll quick_pow(ll a,ll b,ll m){ ll res=1; while(b){ if(b&1) res=(res*a)%m; a=(a*a)%m; b>>=1; } return res%m; } int main(){ scanf("%lld%lld%lld%lld%lld",&n,&x,&y,&a,&b); if(n==1) cout<<x%mod<<endl; else if(n==2) cout<<y%mod<<endl; else{ if(x%mod==0||y%mod==0||a%mod==0) cout<<0<<endl; else{ x%=mod,y%=mod; a=quick_pow(a%mod,b,mod); ll ans1=quick_pow(x,fb1(1,n-1,mod-1),mod)%mod; ll ans2=quick_pow(y,fb1(0,n-1,mod-1),mod)%mod; ll ans3=quick_pow(a,fb2(n-1,mod-1),mod)%mod; //printf("%lld %lld %lld\n",ans1,ans2,ans3); printf("%lld\n",ans1*ans2%mod*ans3%mod); } } return 0; }