题目描述:
请输出(3+√5)^n整数部分最后3位。如果结果不超过2位,请补足前导0.
分析:
我们最容易想到的方法肯定是直接计算这个表达式的值,但是这样的精度是不够的。朴素的算法没有办法得到答案。但是我们根据分析可以发现这个问题不用求出√5的值也可以得到答案。
我们可以发现,将(3+√5)n这个式子展开后就是An+Bn√5的形式。同样的,我们将(3-√5)n这个式子展开后就是An-Bn√5。
因此,(3+√5)n+(3-√5)n=2An是一个整数,其中0<(3-√5)^n <1,是解题的关键。由于(3+√5)n=2An-(3-√5)n,所以(3+√5)^n的整数部分就是2An-1.
根据上面的推导,只要高效的求出An就可以解决这个问题了。由于(3+√5)(n+1)=(3+√5)(3+√5)n=(3+√5) (An+Bn√5),我们可以得到An,Bn,A(n+1),B(n+1)的递推关系。
A(n+1)=3An+5Bn;
B(n+1)=An+3Bn;
A0=1 B0=0;
我们可以用矩阵表示这个递推关系,因此可以使用快速幂运算。因为结果要求的是后三位,所以最后取余1000就行。
#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
struct Node
{
int e[2][2];
Node()
{
memset(e,0,sizeof(e));
}
};
Node mul(Node a,Node b)
{
Node c;
for(int i=0; i<2; i++)
for(int j=0; j<2; j++)
for(int k=0; k<2; k++)
{
c.e[i][j]+=(a.e[i][k]*b.e[k][j]);
}
return c;
}
Node quick_mi(Node a,int b)
{
Node c;
c.e[0][0]=1;
c.e[1][1]=1;
while(b)
{
if(b&1)
c=mul(c,a);
b>>=1;
a=mul(a,a);
}
return c;
}
int main()
{
int n;
while(~scanf("%d",&n))
{
Node A;
A.e[0][0]=3;
A.e[0][1]=5;
A.e[1][0]=1;
A.e[1][1]=3;
A=quick_mi(A,n);
printf("%03d\n",(2*A.e[0][0]-1)%1000);
}
return 0;
}