题目(http://acm.hdu.edu.cn/showproblem.php?pid=3117)
求斐波那契数的前四位和后四位,如果不超过八位就直接输出;
求前四位以前就做过,(http://blog.youkuaiyun.com/aonaigayiximasi/article/details/47615789)
老师教的矩阵连乘感觉很是巧妙啊,原来线性代数也是很有用的。
最后的矩阵的[0][1]位置即是所求,中间用快速幂不断取余。
#include <iostream>
#include <math.h>
#include <stdio.h>
using namespace std;
const int mod=10000;
long long f[100];
struct Matrix
{
long long m[2][2];
};
Matrix p={0,1,
1,1};
Matrix I={1,0,
0,1};
Matrix matrixmul(Matrix a,Matrix b)
{
Matrix c;
for(int i=0;i<2;i++)
{
for(int j=0;j<2;j++)
{
c.m[i][j]=0;
for(int k=0;k<2;k++)
{
c.m[i][j]+=(a.m[i][k]*b.m[k][j])%mod;
}
c.m[i][j]=c.m[i][j]%mod;
}
}
return c;
}
Matrix quickpow(long long n)
{
Matrix m=p,b=I;
while(n>=1)
{
if(n&1)
b=matrixmul(b,m);
n=n>>1;
m=matrixmul(m,m);
}
return b;
}
int main()
{
f[0]=0;
f[1]=1;
int bit;
for(int i=2;i<50;i++)
{
f[i]=f[i-1]+f[i-2];
if(f[i]>=100000000)
{bit=i-1;break;}
}
int n;
while(cin>>n)
{
if(n<=bit)
cout<<f[n]<<endl;
else
{
Matrix tmp=quickpow(n);
int ans_e=tmp.m[0][1];
double x=log10(1/sqrt(5))+n*log10((1+sqrt(5))/2.0);
double ans=x-(int)(x)+3;
ans=(int)(pow(10.0,ans));
cout<<ans<<"...";
printf("%04d\n",ans_e);
}
}
return 0;
}
在网上看别人做这道题,说打表后斐波那契数后四位是15000循环一次,测试了果然存在周期啊。。。
#include <iostream>
#include <math.h>
#include <cstdio>
using namespace std;
int f[15000],fib[40]={0,1};
int main()
{int n;
f[0]=0;f[1]=1;
for(int i=2;i<=14999;i++)
{
f[i]=(f[i-1]+f[i-2])%10000;
}
for(int i=2;i<40;i++)
fib[i]=fib[i-1]+fib[i-2];
while(cin>>n)
{
if(n<40)
cout<<fib[n]<<endl;
else
{
double x=log10(1/sqrt(5))+n*log10((1+sqrt(5))/2.0);
double ans=x-(int)(x)+3;
ans=(int)(pow(10.0,ans));
cout<<ans<<"...";
printf("%04d\n",f[n%15000]);
}
}
return 0;
}