斐波那契变题

斐波那契变题

标题:斐波那契

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

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】

但这个数字依然很大,所以需要再对 p 求模。

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

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

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

资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 2000ms

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

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

方法一:

解析:

f(x) = f(x-1)+f(x-2)–>f(x+1)=f(x)+f(x-1)–>f(x+1)-f(x-1)
Σf(n) = f(n+2)-1
原题目等价于:(f(n+2)-1)%f(m)%p --> m>=n+2,余f(m)无意义
–>(f(n+2)-1)%p
(f(n+2)-1)%f(m)%p --> m<n+2

代码:


public class T9斐波那契 {

    static int n;
    static int m;
    static int p;

    static Long[] longs;


    private static BigInteger fib(int k) {
        for(int i=3;i<=k;i++){
            longs[i]=longs[i-1]+longs[i-2];
        }
        return BigInteger.valueOf(longs[k]);
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        n = scanner.nextInt();
        m = scanner.nextInt();
        p = scanner.nextInt();

        longs = new Long[n+3];
        longs[1]=Long.valueOf(1);
        longs[2]=Long.valueOf(1);

        BigInteger sum=fib(n+2);

        if(m>=n+2) {
            sum = sum.subtract(BigInteger.ONE);
            sum = sum.mod(BigInteger.valueOf(p));
            System.out.println(sum);
        }else{
            BigInteger numB = BigInteger.valueOf(longs[m]);
            sum = sum.mod(numB);
            sum = sum.mod(BigInteger.valueOf(p));
            sum = sum.subtract(BigInteger.ONE);
        }

        System.out.println(sum);

    }

}

但是本方法对于10^18次方的数据来说,一是超时,二是long无法存下这么大的数据,所以最终只能得40分

方法二:

解析

可以通过矩阵快速幂来得到结果,这是最快的解法 O(logn),用该方法可以解决超时问题
矩阵解法:

代码:

public class T9斐波那契2 {

    static long n;
    static long m;
    static long p;

    //矩阵相乘
    public static 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[0][1]=m1.data[1][0]*m2.data[0][0]+m1.data[0][1]*m2.data[1][0];
        ans.data[0][1]=m1.data[1][0]*m2.data[0][1]+m1.data[0][1]*m2.data[1][1];
        return ans;
    }

    //m的m次幂
    public static M mPow(M m,long n){
        M E = new M();//单位矩阵
        E.data[0][0]=1;
        E.data[0][1]=0;
        E.data[1][1]=1;
        E.data[1][0]=0;
        while(n!=0){
            if((n&1)==1){
                E = mul(E,m);
            }
            m=mul(m,m);
            n>>=1;
        }
        return E;
    }

    public static long fib(long i){
        //[1,1]B^(i-2)
        M A = new M();
        A.data[0][0]=1;
        A.data[0][1]=1;
        A.data[1][0]=0;
        A.data[1][1]=0;
        M B = new M();
        B.data[0][0]=1;
        B.data[0][1]=1;
        B.data[1][0]=1;
        B.data[1][1]=0;
        M ans = mul(A,mPow(B,i-2));
        return ans.data[0][0];
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        n = scanner.nextLong();
        m = scanner.nextLong();
        p = scanner.nextLong();



    }

    static class M{
        long data[][] = new long[2][2];
    }

}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值