zoukankan      html  css  js  c++  java
  • 数论+矩阵快速幂|斐波那契|2014年蓝桥杯A组9-fishers

    标题:斐波那契

    斐波那契数列大家都非常熟悉。它的定义是:
    
    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) 取模。
    公式参见【图1.png】
    
    但这个数字依然很大,所以需要再对 mod 求模。
    

    【数据格式】
    输入为一行用空格分开的整数 n m mod (0 < n, m, mod < 10^18)
    输出为1个整数

    例如,如果输入:
    2 3 5
    程序应该输出:
    0

    再例如,输入:
    15 11 29
    程序应该输出:
    25

    资源约定:
    峰值内存消耗 < 256M
    CPU消耗 < 1000ms

    Σf(n)=f(n+2)-1

    尽量用迭代

    规模很大,数据很大

    简单解法,直接计算斐波那契数列 能得一部分分数

    void solve1() {
        LL a = 1;
        LL b = 1;
        //直接计算斐波那契数列 能得一部份分 
        if (m >= n + 2) {
            for (LL i = 3; i <= n + 2; ++i) {
                LL t = a;
                a = b;
                b += t;
            }
            printf("%llu
    ", b % mod - 1);
        } else {//m<n+2
            LL fibM, fibN_2 = 0;
            for (LL i = 3; i <= n + 2; ++i) {
                LL t = a;
                a = b;
                b += t;
                if (i == m) fibM = b;
            }
            fibN_2 = b;
            printf("%llu %llu
    ", fibN_2, fibN_2 % fibM % mod - 1);
        } 
    }
    

    斐波那契数列可以用矩阵运算解出来

    快速斐波那契<--矩阵运算<--快速矩阵幂运算(logn时间复杂度)
    mod带入到矩阵乘法中,每次乘和每次加,都对结果进行模运算->运算数在LL的范围内

    整数快速乘法,并在乘法中加入模运算

    #include <iostream>
    #include <algorithm>
    #include <cstring>
    
    using namespace std;
    
    typedef unsigned long long LL;
    
    LL n, m, mod;
    
    class M {
    public:
        LL data[2][2];
    
        M() { memset(data, 0, sizeof(data)); }
    };
    
    //将两个2*2的矩阵相乘
    M *mul(M *m1, M *m2) {
        M *ans = new M();
        ans->data[0][0] = m1->data[0][0] * m2->data[0][0] + m1->data[0][1] * m2->data[1][0];
        ans->data[0][1] = m1->data[0][0] * m2->data[0][1] + m1->data[0][1] * m2->data[1][1];
        ans->data[1][0] = m1->data[1][0] * m2->data[0][0] + m1->data[1][1] * m2->data[1][0];
        ans->data[1][1] = m1->data[1][0] * m2->data[0][1] + m1->data[1][1] * m2->data[1][1];
        return ans;
    }
    
    //快速乘法
    LL mm(LL a, LL b, LL mod) {
        if (a > b) {
            LL t = a;
            a = b;
            b = t;
        }
        LL x = 0;
        while (b != 0) {
            if ((b & 1) == 1) {
                x = (x + a) % mod;
            }
            a = (a * 2) % mod;
            b >>= 1;
        }
        return x;
    }
    
    //将两个2*2的矩阵相乘
    M *mul(M *m1, M *m2, LL mod) {
        M *ans = new M();
        ans->data[0][0] = (mm(m1->data[0][0], m2->data[0][0], mod) + mm(m1->data[0][1], m2->data[1][0], mod)) % mod;
        ans->data[0][1] = (mm(m1->data[0][0], m2->data[0][1], mod) + mm(m1->data[0][1], m2->data[1][1], mod)) % mod;
        ans->data[1][0] = (mm(m1->data[1][0], m2->data[0][0], mod) + mm(m1->data[1][1], m2->data[1][0], mod)) % mod;
        ans->data[1][1] = (mm(m1->data[1][0], m2->data[0][1], mod) + mm(m1->data[1][1], m2->data[1][1], mod)) % mod;
        return ans;
    }
    
    //m的n次幂log(n) 
    M *mPow(M *m, LL n) {
        M *E = new M();//单位矩阵
        E->data[0][0] = 1;
        E->data[1][1] = 1;
    
        while (n != 0) {
            if (n & 1 == 1) {
                E = mul(E, m);
            }
            m = mul(m, m);//按平方倍增
            n >>= 1;
        }
        return E;
    }
    
    //m的n次幂log(n) 并去模
    M *mPow(M *m, LL n, LL mod) {
        M *E = new M();//单位矩阵
        E->data[0][0] = 1;
        E->data[1][1] = 1;
    
        while (n != 0) {
            if ((n & 1) == 1) {
                E = mul(E, m, mod);
            }
            m = mul(m, m, mod);//按平方倍增
            n >>= 1;
        }
        return E;
    }
    
    //求斐波那契数列
    LL fib(LL i) {
        //[1,1]B^(i-2)
        M *A = new M();
        A->data[0][0] = 1;
        A->data[0][1] = 1;
        M *B = new M();
        B->data[0][0] = 1;
        B->data[0][1] = 1;
        B->data[1][0] = 1;
        M *ans = mul(A, mPow(B, i - 2));
        return ans->data[0][0];
    }
    
    //求斐波那契数列并取模
    LL fib(LL i, LL mod) {
        //[1,1]B^(i-2)
        M *A = new M();
        A->data[0][0] = 1;
        A->data[0][1] = 1;
        M *B = new M();
        B->data[0][0] = 1;
        B->data[0][1] = 1;
        B->data[1][0] = 1;
        M *ans = mul(A, mPow(B, i - 2, mod), mod);
        return ans->data[0][0];
    }
    
    void solve2() {
        if (m >= n + 2) {
            printf("%llu
    ", fib(n + 2, mod) - 1);
        } else {//m<n+2
            LL fibm = fib(m);
            printf("%llu
    ", fib(n + 2, fibm) % mod - 1);
        }
    }
    
    int main(int argc, const char *argv[]) {
        scanf("%llu %llu %llu", &n, &m, &mod);
        solve2();
        return 0;
    }
    
  • 相关阅读:
    观察者模式
    工厂模式
    单例模式
    关于状态机
    关于memset的错误使用
    关于STL容器
    关于内存及其相关
    python学习手册:第十一章——赋值表达式及打印
    python学习手册:第九章——元组、文件及其他
    python学习手册:第七章——字符串
  • 原文地址:https://www.cnblogs.com/fisherss/p/10473570.html
Copyright © 2011-2022 走看看