HDU 5667 Sequence 矩陣快速冪 + 費馬小定理
阿新 • • 發佈:2019-01-31
olion August will eat every thing he has found.
Now there are many foods,but he does not want to eat all of them at once,so he find a sequence.
fn=⎧⎩⎨⎪⎪1,ab,abfcn−1fn−2,n=1n=2otherwise
He gives you 5 numbers n,a,b,c,p,and he will eat fn foods.But there are only p foods,so you should tell him fn
mod p.
Input
The first line has a number,T,means testcase.
Each testcase has 5 numbers,including n,a,b,c,p in a line.
1≤T≤10,1≤n≤1018,1≤a,b,c≤109,p is a prime number,and p≤109+7
.
Output
Output one number for each case,which is fn
mod p.
Sample Input
1 5 3 3 3 233
Sample Output
190
題解:看到表示式 很容易我們可以想到 取一下 log 然後就可以得到 f[n] = c*f[n - 1] + f[n - 2] + b; 然後構造矩陣就可以了
比較坑的是,a%p==0 的時候要判斷一下,因為 n>=2 的每一項取模之後都為0了 但是 在快速冪中 是無法得到0 的
#include<iostream> #include<cstdio> typedef long long ll; using namespace std; ll n,a,b,c,p; struct node{ ll mat[4][4]; }ans,res; node cul(node x,node y) { node z; for(int i=1;i<=3;i++) { for(int j=1;j<=3;j++) { z.mat[i][j]=0; for(int k=1;k<=3;k++) z.mat[i][j]=(z.mat[i][j]+x.mat[i][k]*y.mat[k][j]%(p-1))%(p-1); } } return z; } ll J_ksm() { ll m=n-2; while(m) { if(m&1) res=cul(res,ans); m>>=1; ans=cul(ans,ans); } // cout<<res.mat[1][1]<<" "<<res.mat[1][3]<<endl;; return (res.mat[1][1]*b%(p-1)+res.mat[1][3]*b%(p-1))%(p-1); } ll ksm(ll x,ll y) { ll sum=1; while(y) { if(y&1) sum=(sum*x)%p; y>>=1; x=x*x%p; } return sum; } int main() { int T; scanf("%d",&T); while(T--) { scanf("%lld%lld%lld%lld%lld",&n,&a,&b,&c,&p); ans.mat[1][1]=c,ans.mat[1][2]=1,ans.mat[1][3]=1; ans.mat[2][1]=1,ans.mat[2][2]=0,ans.mat[2][3]=0; ans.mat[3][1]=0,ans.mat[3][2]=0,ans.mat[3][3]=1; for(int i=1;i<=3;i++) { for(int j=1;j<=3;j++) { if(i==j) res.mat[i][j]=1; else res.mat[i][j]=0; } } if(n==1) printf("1\n"); else if(n==2) printf("%lld\n",ksm(a,b)); else if(a%p==0) printf("0\n"); else { ll cnt=J_ksm(); // cout<<cnt<<endl; printf("%lld\n",ksm(a,cnt)); } } return 0; }