问题描述:Fibonacci数列的递推公式为:Fn=Fn-1+Fn-2,其中F1=F2=1。当n比较大时,Fn也非常大,现在我们想知道,Fn除以10007的余数是多少。(1 <= n <= 1000000)
开始的思路是直接利用递推公式算出第n个数,在求出余数。但不幸的是,得分没有得全。过后想了想,是由于当n过大时,Fn太大,基本的数据结构不能存储下,造成溢出,程序无法得出正确答案。
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
long f1=1;
long f2=1;
long n;
long fn=0;
long i ;
Scanner scanner=new Scanner(System.in);
n=scanner.nextLong();
if(n==1||n==2)
{
fn=1;
}
for (i = 3; i <= n; i++) {
fn=f1+f2;
f1=f2;
f2=fn;
}
System.out.println(fn%10007);
}
}
后来看了思路,取余运算中存在定理:(a + b) % p = (a % p + b % p) % p ,相当与分配率,一个数取p的余数,这个数可以看做a+b,则余数等于a取p的余数加上b取p的余数再对p取余数。而题目中的Fibonacci数列正好满足这一规则。我们只需要用一个数组保存每个Fn%10007的余数,求第n个余数就是求解(Fn-1%10007+Fn-2%10007)%10007。这样数组中保存的余数的最大值不会超过10007,完全不会溢出。
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
int n;
final int num=10007;
Scanner scanner =new Scanner(System.in);
n=scanner.nextInt();
if(n==1||n==2)
{
System.out.println(1);
}else {
int[] a=new int[n];
a[0]=1;
a[1]=1;
for(int i=2;i<n;i++)
{
a[i]=(a[i-1]+a[i-2])%num;
}
System.out.println(a[n-1]);
}
}
}