Sicily E1_fib1 斐波那契数列取模(大数)分治算法


思路与源代码参考地址在此


(1)由于有如下性质:

(n*m)%c=[(n%c)*(m%c)]%c

(n+m)%c=[(n%c)+(m%c)]%c ,

计算过程中可以随时取模,而不影响最终的结果。


(2)利用矩阵求斐波那契数列:

(3)

二分的原理:要求矩阵的N次方A(N),设i=N/2。若N%2==1, 则 A(N)=A(i)*A(i)*A(1);若N%2==0, 则 A(N)=A(i)*A(i)

基于二进制的原理:将N拆为二进制数,譬如13=1101那么 A^13= A^8 * A^4 * A^1 (这里^表示幂运算)


也就是说,由A^1开始,自乘得到A^2,然后自乘得到A^4,如果N对应位为1,则将这个结果乘到目标上去
这样的话,将所有乘法改为模乘,就可以得到一个较大Fibonacci数除以M的余数


实现代码:


#include
using namespace std;

#define mod 1000000007
// f(n)=f(i)*f(n-i-1)+f(i+1)*f(n-i)
int tempA, tempB, tempC, tempD;
void func(int n, int &a, int &b, int &c, int &d){
    if (n == 1){
        a = 0;
        b = c = d = 1;
        return;
    }
    if (n % 2 == 0){
        func(n / 2, a, b, c, d);
        tempA = a*a + b*c;
        tempB = b*(a + d);
        tempC = c*(a + d);
        tempD = c*b + d*d;
        a = tempA % mod;
        b = tempB % mod;
        c = tempC % mod;
        d = tempD % mod;
        return;
    }
    else{
        func(n / 2, a, b, c, d);
        tempA = b*(a + d);
        tempB = a*a + b*(a + c + d);
        tempC = c*b + d*d;
        tempD = c*(a + b + d) + d*d;
        a = tempA % mod;
        b = tempB % mod;
        c = tempC % mod;
        d = tempD % mod;
        return;
    }
}
int main(){
    int n;
    while (cin >> n&&n != 0){
        int a, b, c, d;
        if (n <= 2){
            cout << 1 << endl;
            continue;
        }
        else n -= 2;
        func(n, a, b, c, d);
        cout << (b + d) % mod << endl;
    }
    return 0;
}           



你可能感兴趣的:(数学与数论)