JAVA算法练习(12):斐波那契

        实力不行,没写出来跑满的,只跑了 60% ;

------文章底部代码分享

 一、题目

标题:斐波那契
斐波那契数列大家都非常熟悉。它的定义是:

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)取模。
公式参见下图:

但这个数字依然很大,所以需要再对mod 求模。
【数据格式】
输入为一行用空格分开的整数 n m mod (O<n, m, mod <10^18)输出为1个整数
例如,如果输入:
2 3 5
程序应该输出:
0
再例如,输入:
15 11 29
程序应该输出:
25
资源约定:
峰值内存消耗(含虚拟机) <256M
CPU消耗 < 2000ms

请严格按要求输出,不要画蛇添足地打印类似:“请您输人...”的多余内容。

所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意:不要使用package语句。不要使用jdk1.7及以上版本的特性。
注意:主类的名字必须是:Main,否则按无效代码处理。

二、解题

2.1

        由题可知,斐波那契的规律是:

        f(1) = f(2) = 1;

        f(x) = f(x-1) + f(x-2);

        

        如果是是求总和我们需要把 f(x) - f(1) 范围内所有的数加起来,这无疑是十分浪费时间的,故我们通过其规律进行化简,如下图:

         最后得出简化公式 Σf(x) = f(x+1) - 1 ;

2.2

        写代码的时候,第一步将所需的三个数读入,因为 mod 超出了 long 类型范围,故需要 BigInteger 类型;

 2.3

        做完这一步之后我们又要考虑使用什么方法来对其进行计算,如果是利用暴力解法无疑会导致程序时间的延长,故这边选用了线性代数的矩阵相乘求斐波那契;

        斐波那契----矩阵快速幂:

2.4

        建立一个初始的只有 f(1) 跟 f(2) 斐波那契数列;

        因为如果 m 大于 n + 2 的值,那么求余返回的也是本身导致毫无意义,故使其分为两个分支一个需要计算 f(m) 一个只计算 f(n+2) ;

        在计算辅助矩阵的幂次方数时,我们可以发现有一个规律,f(x) = f(1) * 辅助矩阵^(n-2) ,所以我们在计算辅助矩阵幂次方的时候只需要传入 x-2 ;

 2.5

        确定辅助矩阵时要注意一次方的情况,这边是编写了一个单位矩阵进行辅助;

 2.6

        计算矩阵时要注意不要乘错数即可,矩阵乘法的计算规则是同行乘同列;

 2.7

        最后按要求输出;( 注:m < n + 2 时取模没有意义,可以不用做 )

 

三、代码分享

import java.math.BigInteger;
import java.util.Scanner;

public class Main{
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        long n, m;
        n = sc.nextLong();
        m = sc.nextLong();
        BigInteger mod = BigInteger.valueOf( sc.nextLong() );
        BigInteger[][] fib = {
                { BigInteger.ONE , BigInteger.ONE },
                { BigInteger.ZERO , BigInteger.ZERO }
        };

        if ( n + 2 > m ){
            BigInteger[][] M = count( fib , mPow( n ) );
            BigInteger[][] N = count( fib , mPow( m - 2 ) );
            System.out.println( M[0][0].subtract( BigInteger.ONE ).mod( N[0][0] ).mod( mod ) );
        }else {
            BigInteger[][] M = count( fib , mPow( n ) );
            System.out.println( M[0][0].subtract( BigInteger.ONE ).mod( mod ) );
        }
    }

    public static BigInteger[][] mPow( long n ){
        BigInteger[][] E = {
                { BigInteger.ONE , BigInteger.ZERO },
                { BigInteger.ZERO , BigInteger.ONE }
        };
        BigInteger[][] fibM = {
                { BigInteger.ONE , BigInteger.ONE },
                { BigInteger.ONE , BigInteger.ZERO }
        };
        for ( long i = 0 ; i < n ; i++ ){
            E = count( fibM , E );
        }
        return E;
    }

    private static BigInteger[][] count( BigInteger[][] A , BigInteger[][] B ){
        BigInteger[][] newM = new BigInteger[2][2];
        newM[0][0] = A[0][0].multiply( B[0][0] ).add( A[0][1].multiply( B[1][0] ) );
        newM[0][1] = A[0][0].multiply( B[0][1] ).add( A[0][1].multiply( B[1][1] ) );
        newM[1][0] = A[1][0].multiply( B[0][0] ).add( A[1][1].multiply( B[1][0] ) );
        newM[1][1] = A[1][0].multiply( B[0][1] ).add( A[1][1].multiply( B[1][1] ) );
        return newM;
    }

}

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jc_caterpillar

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值