在Google Code Jam 2008第1A轮,there is problem:
计算前三位数 数字的小数点 (3 + SQRT(5))^ n的
n可以是1000000的大数字
例如:如果n = 2则(3 + sqrt(5))^ 2 = 27 .4164079 ...答案为027.
对于n = 3:(3 + sqrt(5))^ 3 = 3 935 .73982 ...答案是935.
其中一个解决方案是创建矩阵M 2x2:[[0,1],[ - 4,6]],而不是计算矩阵P = M ^ n,其中计算由模1000执行。
结果是(6*P[0,0] + 28*P[0,1] - 1)
mod 1000.
谁能解释我这个解决方案?
答案 0 :(得分:7)
我将提出一种解决这个问题的方法,甚至不用理解解决方案。
假设您熟悉斐波那契数字:
ghci> let fib = 0 : 1 : zipWith (+) fib (tail fib)
ghci> take 16 fib
[0,1,1,2,3,5,8,13,21,34,55,89,144,233,377,610]
并熟悉其封闭的表格形式:
ghci> let calcFib i = round (((1 + sqrt 5) / 2) ^ i / sqrt 5)
ghci> map calcFib [0..15]
[0,1,1,2,3,5,8,13,21,34,55,89,144,233,377,610]
你注意到((1 + sqrt 5)/ 2) n 和(3 + sqrt 5) n 的相似性。
从这里可以猜测,可能有一系列类似于斐波那契来计算这个。
但是什么系列?所以你计算了前几个项目:
ghci> let calcThing i = floor ((3 + sqrt 5) ^ i)
ghci> map calcThing [0..5]
[1,5,27,143,751,3935]
猜测公式的形式如下:
东西 n = a * thing n-1 + b * thing n-2
我们有:
27 = a * 5 + b * 1
143 = a * 27 + b * 5
我们求解线性方程组得到:
东西 n = 4 * thing n-1 + 7 * thing n-2 (a = 4,b = 7)< / p>
我们检查:
ghci> let thing = 1 : 5 : zipWith (+) (map (* 4) (tail thing)) (map (* 7) thing)
ghci> take 10 thing
[1,5,27,143,761,4045,21507,114343,607921,3232085]
ghci> map calcThing [0..9]
[1,5,27,143,751,3935,20607,107903,564991,2958335]
然后我们发现遗憾的是,这并不能计算我们的功能。但是,我们对它获得最正确的数字这一事实感到欢欣鼓舞。不理解为什么,但在这个事实的鼓舞下,我们尝试类似的东西。要查找修改后的公式的参数:
东西 n = a * thing n-1 + b * thing n-2 + c
然后我们到达:
东西 n = 6 * thing n-1 - 4 * thing n-2 + 1
我们检查一下:
ghci> let thing =
1 : 5 : map (+1) (zipWith (+)
(map (*6) (tail thing))
(map (* negate 4) thing))
ghci> take 16 thing == map calcThing [0..15]
True
答案 1 :(得分:3)
我不知道如何解释,但问题的作者已撰写this analysis。
答案 2 :(得分:3)
只是回答一个非常古老的问题:
感谢yairchu我有想法在维基百科页面上重新阅读Binet's formula的证明。它不是那么清楚,但我们可以使用它。
我们在维基百科页面上看到一个封闭的表格,其中“通过舍入计算”:F n =⌊φ/√5⌋ n 。 如果我们可以用3 +√5代替φ/√5(称为后者x)。我们可以很容易地计算x n 的最低值,特别是mod 1000,通过在我们新构造的序列中找到第n个项(这是F的类比(后面我们称之为模拟U))。
我们要找的是什么序列?好吧,我们将尝试遵循Binet公式的证明。我们需要一个以x为根的二次方程。假设x 2 = 6 x-4,这个根有x和y:= 3 - √5。方便的部分现在是:
定义U n (对于每个a和b),例如:
U n = a x n + b y n
根据x和y的定义,你可以看到
U n = 6 U n-1 - 4 U n-2
现在我们可以自由选择a和b。我们需要U n 为整数,所以我建议选择a = b = 1。现在是U 0 = 2,U 1 = 6,U 2 = 28 ...
我们仍然需要通过四舍五入来进行计算。你可以看到y n &lt;每n为1(因为y≅0.76<1)因此U n = x n + y n =⌈x n ⌉。
如果我们可以计算U n ,我们可以找到⌊x n ⌋,只需减去1。
我们可以通过它的递归公式计算U n ,但这需要O(n)计算时间。我们可以做得更好!
为了计算这样的递归公式,我们可以使用矩阵:
⌈ 0 1⌉ ⌈ U(n-1) ⌉ ⌈ U(n) ⌉
⌊-4 6⌋ ⌊ U(n) ⌋ = ⌊U(n+1)⌋
调用此矩阵M.现在M *(U(1),U(2))计算(U(2),U(3))。 现在我们可以计算P = M n-1 (注意我使用的是一个小于n,你可以看到这是正确的,如果你测试小的情况:n = 0,n = 1,n = 2)P *(6,28)现在给出了序列的第n和第(n + 1)项:
(P *(6,28)) 0 - 1 =⌊x n ⌋
现在我们可以把所有mod 1000(这简化了计算(很多))并且我们在计算时间O(log(n))中得到了期望的结果(或者甚至更好地利用矩阵幂的计算奇迹(在循环有限域上))。这就解释了这个奇怪的解决方案,我想。