2020牛客寒假集訓第一場J題——矩陣快速冪

 題目鏈接:

https://ac.nowcoder.com/acm/contest/3002/J

題目描述:

給你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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章