1. 程式人生 > 實用技巧 >試題 歷屆試題 斐波那契(矩陣快速冪)

試題 歷屆試題 斐波那契(矩陣快速冪)

問題描述   斐波那契數列大家都非常熟悉。它的定義是:

  f(x) = 1 .... (x=1,2)
  f(x) = f(x-1) + f(x-2) .... (x>2)

  對於給定的整數 n 和 m,我們希望求出:
  f(1) + f(2) + ... + f(n) 的值。但這個值可能非常大,所以我們把它對 f(m) 取模。
  公式如下


  但這個數字依然很大,所以需要再對 p 求模。 輸入格式   輸入為一行用空格分開的整數 n m p (0 < n, m, p < 10^18) 輸出格式   輸出為1個整數,表示答案 樣例輸入 2 3 5 樣例輸出 0 樣例輸入 15 11 29 樣例輸出 25 思路:由規模知要使用矩陣快速冪,前n項斐波那契和有sum=f[n+2]-1;則問題轉化為求f[n+2]%f[m]%p; 但是程式碼只有60分,最後兩個點沒過,看了很久沒找出來,先放著吧
#include<bits/stdc++.h>
using
namespace std; typedef unsigned long long int ll; struct mat{ ll m[3][3]; }unit; ll n,m,p,mod; ll ksm(ll a1,ll a2){///快速乘法中間取模防止溢位 ll res=0; if(a1>a2)swap(a1,a2); while(a2!=0){ if(a2&1){res=(res+a1)%mod;} a1=(a1+a1)%mod; a2>>=1; } return res; } mat mul(mat a1,mat a2){ mat temp;
//memset(temp.m,0,sizeof(temp.m)); for(int i=1;i<=2;i++){ for(int j=1;j<=2;j++){ temp.m[i][j]=0; for(int k=1;k<=2;k++){ temp.m[i][j]=(temp.m[i][j]+ksm(a1.m[i][k],a2.m[k][j]))%mod; } } } return temp; } int quick_mat(ll n){ mat ans; memset(ans.m,
0,sizeof(ans.m)); for(int i=1;i<=2;i++)ans.m[i][i]=1; unit.m[1][1]=1;unit.m[1][2]=1;unit.m[2][1]=1;unit.m[2][2]=0; while(n!=0){ if(n&1)ans=mul(ans,unit); unit=mul(unit,unit); n>>=1; } return ans.m[1][2]%mod;///第一行第二列為f[n] } int main(){ ll sum=0; cin>>n>>m>>p; if(n+2<=m){///若n+2<=m 則無需對m進行取模,直接對p取模 mod=p; cout<<(quick_mat(n+2)-1)%p<<endl; return 0; } mod=-1; mod=quick_mat(m);///先算出f(m) sum=quick_mat(n+2); cout<<(sum-1)%p<<endl; return 0; }