实力不行,没写出来跑满的,只跑了 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;
}
}