| Time Limit: 1000MS | Memory Limit: 65536K | |
| Total Submissions: 8570 | Accepted: 6093 |
Description
In the Fibonacci integer sequence, F0 = 0, F1 = 1, and Fn = Fn − 1 + Fn − 2 for n ≥ 2. For example, the first ten terms of the Fibonacci sequence are:
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, …
An alternative formula for the Fibonacci sequence is
.
Given an integer n, your goal is to compute the last 4 digits of Fn.
Input
The input test file will contain multiple test cases. Each test case consists of a single line containing n (where 0 ≤ n ≤ 1,000,000,000). The end-of-file is denoted by a single line containing the number −1.
Output
For each test case, print the last four digits of Fn. If the last four digits of Fn are all zeros, print ‘0’; otherwise, omit any leading zeros (i.e., print Fn mod 10000).
Sample Input
0 9 999999999 1000000000 -1
Sample Output
0 34 626 6875
Hint
As a reminder, matrix multiplication is associative, and the product of two 2 × 2 matrices is given by
.
Also, note that raising any 2 × 2 matrix to the 0th power gives the identity matrix:
.
这道题是矩阵乘法快速幂,简单举个例子,比如你想计算a的9次方,先有a*a变成a的2次方,再相乘变成a的4次方,再相乘变成a的8次方,再乘以a变成a的9次方。
这里还用到一种思想就是二进制如9的二进制位1001一共有4位,第一位肯定是1,那么就为a,第二位是0,就把用前面得到的数相乘,a*a=a^2,第三位也是0,继续相乘a^2*a^2=a^4,第四位是1,就a^4*a^4*a=a^9。
我们可以正着写,也可以反着写(下面代码是反着写的),定义一个ret和一个first,ret为最后结果,每次first相乘先让first为a,9,的第四位是1,所以ret为a^1,first为a^2;第三位为0,ret不变,fitst为a^4,第二位为0,ret不变,fitst为a^8;第一位为1,ret=ret*first=a*a^8=a^9,first=a^16。
或者这么说吧,就是 1*a^8 * 0*a^4 * 0*a^2 * 1*a^1
这里a是一个矩阵,那么就要再加上矩阵相乘。
注意最后的答案要mod10000。
另外我最开始的时候没有用这种方法,像这种有规律递归的算法再mod一个数,一般也都是有规律可循的,所以我先写一个计算斐波那契的程序,且mod10000,然后当这个数为1的时候,输出这是第几个数,后来发现输出的是1,2,15001,15002,30001,30002……说明这个数是15000循环一次,且0和15000对应的数都是0。(有的可能0和一次循环15000的结果不一样,虽然这道题不存在这种情况,但是有必要注意一下。)
先给出矩阵相乘的AC代码:
#include<cstdio>
#include<cstring>
using namespace std;
struct node
{ int f[2][2];
};
node mul(node a,node b) //定义一个相乘的方法
{ int i,j,k;
node m;
for(i=0;i<=1;i++) //得到的矩阵的第i行,第j列的数
{ for(j=0;j<=1;j++)
{ m.f[i][j]=0;
for(k=0;k<=1;k++) //前面矩阵的第i行乘以后面矩阵的第j列
m.f[i][j]+=a.f[i][k]*b.f[k][j];
m.f[i][j]%=10000; //取模
}
}
return m;
}
int main()
{ int n,l;
while(~scanf("%d",&n) && n>=0)
{ if(n<=1) //如果输入为1,输出的f(1)=1,输入为0,输出的f(0)=0
printf("%d\n",n);
else
{ node ret;
node first;
n--; //因为最开始的时候让ret=1,所以最后乘出的结果也要除以一个基本矩阵,也就是说求n-1即可
first.f[0][0]=first.f[0][1]=first.f[1][0]=ret.f[0][0]=ret.f[0][1]=ret.f[1][0]=1;
first.f[1][1]=ret.f[1][1]=0;
while(n)
{ if(n&1) //如果二进制最后一位是1的话,这句话等同于n%2==1
ret=mul(ret,first); //乘以first矩阵
first=mul(first,first); //first矩阵自乘
n/=2;
}
printf("%d\n",ret.f[0][1]);
}
}
}
然后是利用循环规律的AC代码:
#include<cstdio>
int f[15005];
int main()
{ int i,j,n;
f[0]=0;
f[1]=f[2]=1;
for(i=3;i<=15000;i++) //每15000循环一次
f[i]=(f[i-1]+f[i-2])%10000;
while(~scanf("%d",&n)&&n>=0)
{ n=n%15000;
printf("%d\n",f[n]);
}
}

本文介绍了一种高效计算斐波那契数列中任意项最后四位数字的方法,通过矩阵快速幂运算实现,并提供了两种AC代码示例。
7425

被折叠的 条评论
为什么被折叠?



