末三位整数

本文介绍了如何解决编程挑战中关于求(3 + √5)^n小数点前三位的整数部分的问题。通过将问题与斐波那契数列联系起来,找到递推公式,然后利用数列的周期性,有效计算出末三位数值。这种方法避免了直接计算带来的精度和效率问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

    这是编程挑战-高校俱乐部的题目。求(3 + √5)^n的小数点前(整数部分)的最低3位。 例如:(3 + √5)^5 = 3935.73982…则输出935 而(3 + √5)^2 = 27.4164079.. 则输出027。 输入格式: 多组数据,每组一行包含一个正整数n, 2<=n<=2000000000。 输出格式: 每组数据输出一行,恰好包含3个数字。 

    看到这个题,感觉就是完全不是考验编程能力,而是更多考验数学能力。很明显,要是一个没有学过高等数学的人,基本不太可能解决这个问题(当然了,学了也解决不了的人也存在)。看这个题,输入变量n的变化范围很大,显然,这个题是有简便的解法的。

    笨办法是把这个数求出来,不过显然有难度。先不说这个复杂度,就是n大到一定程度的时候,计算机就不好表示这个数了,而且由于误差的存在,结果很有可能是错的。所以要换个思路。

    我看到这个题,想到的是菲波那契数列。为什么呢?因为如果a0=a1=1,那么n>1,an=((1+√5)/2)^n+(1-√5)/2)^n。an其实是个整数,但是却可以用两个无理数来表示。那这里是不是也有用呢。刚好,3 -√5是个小于1的小数,若有an=(3+√5)^n+(3-√5)^n这样类似的有理数序列,那不就很好算了,而且没有误差。很容易可以看出an是个整数,而且a0=2,a1=6。那现在问题就是,怎么来快速的求an?再参考菲波那契数列,通式怎么表达的。a[n]=a[n-1]+a[n-2]。那这里也可以用类似的表达式,a[n]=p*a[n-1]+q*a[n-2]。对于这样的数列,有通式a[n]=t*x1^n+s*x2^n。其中x1,x2是方程x^2=p*x+q的两个根。对应上已有的通式,可得到t=s=1, x1=3+√5, x2=3-√5,那么p=6,q=-4,即a[n]=6*a[n-1]-4*a[n-2]。由此公式可以从a0,a1开始很方便的得到任意an的值。

    既然an求出来了,那么我们需要的就是,(3+√5)^n=an-(3-√5)^n。可以看出,等式的第二项是个小于1的小数。故而左边的整数部分的末3位就等于an-1的末3位。取bn=an%1000,再迭代求解,可以得到an的末3为整数值。

    当然了,如果是一个个的迭代求解,事件复杂度就是O(N)了,这是绝对无法忍受的。很容易看出来,bn会是个循环的周期序列,经过验证,循环从b3开始,周期是100,这个循环部分的数字如下所示:

144 752 936 608 904 992 336 048 944 472 056 448 464 992 096 608 264 152 856 528 744 352 136 408 904 792 136 648 344 472 456 848 264 192 096 808 464 552 456 528 344 952 336 208 904 592 936 248 744 472 856 248 064 392 096 008 664 952 056 528 944 552 536 008 904 392 736 848 144 472 256 648 864 592 096 208 864 352 656 528 544 152 736 808 904 192 536 448 544 472 656 048 664 792 096 408 064 752 256 528

    从最后一个数开始,就会又从144开始不断循环。由此可以得到n>3时bn的值。

    至此,这个问题已经解决了,具体代码如下所示:

<pre name="code" class="cpp">#define LIMIT 1000
#define TS 100//cycle is 100
/*
 *consider a[n]=(3+√5)^n+(3-√5)^n
 *then, a[n]=6*a[n-1]-4*a[n-2], a[0]=2, a[1]=6
 *(3-√5)^n is an decimal <1, so (3+√5)^n=a[n]-(3-√5)^n
 *the z number of it is a[n]-1
 *According to a test, a[n]%1000 is a cycle of 100 from a[3]=144
 *so n>=3, a[n]%1000=a[(n-3)%100]%1000
*/
//2<=n<=2,000,000,000
int last3Num(int n){
    int a, b, c;
    if(n==2)
        return 27;
    a=6;
    b=28;
    n=(n-3)%TS;
    for(; n>=0; n--){
        c=6*b-4*a+4*LIMIT;
        c%=LIMIT;
        a=b;
        b=c;
    }
    return (LIMIT+b-1)%LIMIT;
}






评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值