题目大意:
计算
(3+5–√)n
(
3
+
5
)
n
整数部分末三位。
题解:
题解原网址https://code.google.com/codejam/contest/32016/dashboard#s=a&a=2
设
α=3+5–√
α
=
3
+
5
,
β=3−5–√
β
=
3
−
5
,
Xn=αn+βn
X
n
=
α
n
+
β
n
可证明
Xn
X
n
为整数(二项式定理)
∵0<βn<1 ∵ 0 < β n < 1
∴ αn α n 的整数部分一定等于 Xn−1 X n − 1
Solution1:(共轭)
设
αn=an+bn5–√
α
n
=
a
n
+
b
n
5
,
βn=an−bn5–√
β
n
=
a
n
−
b
n
5
∴Xn=2an
∴
X
n
=
2
a
n
又
∵αn+1=(3+5–√)(an+bn5–√)=(3an+5bn)+(an+3bn)5–√
∵
α
n
+
1
=
(
3
+
5
)
(
a
n
+
b
n
5
)
=
(
3
a
n
+
5
b
n
)
+
(
a
n
+
3
b
n
)
5
∴an+1=3an+5bn
∴
a
n
+
1
=
3
a
n
+
5
b
n
,
bn+1=an+3bn
b
n
+
1
=
a
n
+
3
b
n
初始状态: α0=1 α 0 = 1 ,
可使用矩阵快速幂,时间复杂度 O(logn) O ( l o g n )
方法2:
∵α+β=6
∵
α
+
β
=
6
,
αβ=4
α
β
=
4
所以α和β是
x2−6x+4=0
x
2
−
6
x
+
4
=
0
的两个根
∴α2=6α−4
∴
α
2
=
6
α
−
4
,
β2=6β−4
β
2
=
6
β
−
4
∴αn+2=6αn+1−4αn
∴
α
n
+
2
=
6
α
n
+
1
−
4
α
n
,
βn+2=6βn+1−4βn
β
n
+
2
=
6
β
n
+
1
−
4
β
n
两式相加,得:
所以可使用矩阵乘法:
方法3:(方法2存在循环,可优化)
我们只需要最后结果的最后3位,经过法2的多次计算后发现,结果从
n=4
n
=
4
至
n=103
n
=
103
是一个长度为100的循环,然后继续下去。
如果n很大,输出
(n−3)mod100+3
(
n
−
3
)
m
o
d
100
+
3
代码:
#include<cstdio>
#include<vector>
using namespace std;
typedef vector<int> Vector;
typedef vector<Vector> Matrix;
Matrix operator * (Matrix a,Matrix b)
{
int as1=a.size(),as2=a[0].size(),bs1=b.size(),bs2=b[0].size();
if(as2!=bs1)
return Matrix(0,Vector(0));
Matrix ret(as2,Vector(bs1,0));
for(int i=0;i<as1;i++)
for(int j=0;j<bs2;j++)
for(int k=0;k<as2;k++)
ret[i][j]=(ret[i][j]+(a[i][k]*b[k][j])%1000)%1000;
return ret;
}
Matrix pow(Matrix a,int b)
{
Matrix c(a.size(),Vector(a.size(),0));
for(int i=0;i<(int)a.size();i++)
c[i][i]=1;
for(;b;b>>=1,a=a*a)
if(b&1)
c=c*a;
return c;
}
namespace SolutionA
{
int solve(int n)
{
Matrix a(2,Vector(2,0));
a[0][0]=3;a[0][1]=5;
a[1][0]=1;a[1][1]=3;
a=pow(a,n);
return (a[0][0]*2+999)%1000;
}
}
namespace SolutionB
{
int solve(int n)
{
Matrix b(2,Vector(2));
b[0][0]=6;b[0][1]=-4;
b[1][0]=1;b[1][1]=0;
b=pow(b,n);
int ret=b[1][0]*6+b[1][1]*2+999;
while(ret<0)
ret+=1000;
return ret%1000;
}
}
namespace SolutionC
{
int solve(int n)
{
if(n>103)
n=(n-3)%100+3;
return SolutionB::solve(n);
}
}
int main()
{
int T,n;
scanf("%d",&T);
for(int i=1;i<=T;i++)
{
scanf("%d",&n);
//printf("Case #%d: %03d\n",i,SolutionA::solve(n));
//printf("Case #%d: %03d\n",i,SolutionB::solve(n));
printf("Case #%d: %03d\n",i,SolutionC::solve(n));
}
return 0;
}