1. 程式人生 > >矩陣快速冪法+斐波那契數列餘數

矩陣快速冪法+斐波那契數列餘數

#include<stdio.h>
	
	struct mar
	{
		long long a[2][2];
	};
mar mar_mul(mar x,mar y);
int Fmod(long long n);

int main()
{
	int t,i;
	long long b[100];
	scanf("%d",&t);
	for(i=0;i<t;i++)
	scanf("%lld",&b[i]);
	for(i=0;i<t;i++)
	printf("%d\n",Fmod(b[i]));
	return 0;
}
mar mar_mul(mar x,mar y)
{
	mar latest;
	latest.a[0][0]=(x.a[0][0]*y.a[0][0]+x.a[0][1]*y.a[1][0])%100000007;//此步驟見下方詳解
	latest.a[0][1]=(x.a[0][0]*y.a[0][1]+x.a[0][1]*y.a[1][1])%100000007;
	latest.a[1][0]=(x.a[1][0]*y.a[0][0]+x.a[1][1]*y.a[1][0])%100000007;
	latest.a[1][1]=(x.a[1][0]*y.a[0][1]+x.a[1][1]*y.a[1][1])%100000007;
	return latest;
}

int Fmod(long long n)  
{  
    long long N=n-1;
	int ans;
	mar res,f; 
	res.a[0][0]=1;
	res.a[0][1]=0;
	res.a[1][0]=0;
	res.a[1][1]=1;
	f.a[0][0]=1;
	f.a[0][1]=1;
	f.a[1][0]=1;
	f.a[1][1]=0;
    while(N>0)  
    {  
        if(N%2!=0)
        res=mar_mul(res,f);      
        N/=2; 
        f=mar_mul(f,f);  
    }  
    
    return res.a[0][0];  
}  


快速冪取模演算法的原理為ac%b=(a%b)*(c%b)

此處矩陣快速冪與之相似,但由於有了加法導致理解困難,事實上我們可以證明對於有限次四則運算該演算法都是正確的,由於斐波那契數列“公比”矩陣為[1 1\n1 0],對於一開始的四個元素,必定是小於題目要求的除數,在上述程式碼中為100000007,故%運算子對其無影響,而對於之後得到的矩陣來說,每個元素必定由之前矩陣的元素經過有限次四則運算得到的,又由於((a%mod)*(b%mod)+(c%mod)*(d%mod))%mod=(a*b%mod+c*d%mod)%mod=(ab+cd)%mod,故只需對矩陣每一個元素關於mod取餘,最後即可得到斐波那契數列的第n項對mod取餘的結果。