基于Fibonacci序列变化的算法任务

时间:2015-03-01 17:42:03

标签: algorithm

  

给出参数C和M,帮助解密加密列表   整数。前一个参数用于生成{a_n}和{s_n}   序列,定义如下:

     
      
  • a_1 = a_2 = 1
  •   
  • forall n> = 1:a_(n + 2)= C * a_(n + 1)+ a_n
  •   
  • forall n:s_n = a_1 + a_2 + a_3 + ... + a_n
  •   
     

密文由T个自然数组成。他们每个都加密   一个结果号码。为了恢复原始的x值,它是   确定以下操作的结果所必需的:s_x mod   中号

     

输入:两个自然数C和M,T表示测试次数和T.   仅包含一个x数字的行。

     

1 <= C,M <= 10 ^ 18
1 <= T <= 1000
1 <= x <= 10 ^ 18

     

示例输入:

     

1 10
5
2
3
4
10
1

     

示例输出:

     

2
4
7
3
1

这是一个出现在Deadline24算法竞赛中的问题,该竞赛今天上午采取了一些措施,并且为了所有圣洁的爱,我无法想到任何修剪计算的方法,所以在最糟糕的情况下,你不必做10 ^ 18次操作。

任何蛮力方法都会立即被删除,因此这是一种天真的递归方法。我们可能会注意到序列是Fibonacci序列的一个变体,但它没有多大帮助,因为具有C!= 1的序列与常规Fibonacci序列不同,因此我们无法应用任何近似值像Binet的Fibonacci数公式来计算F_(n + 2) - 1,它通常是前n个Fibonacci数的总和。

我想过用C语言来表达这些术语并应用一些快速的modpow但是由于它很慢(我们仍然需要计算每个项的系数,这是最后的每个幂的循环)总和)并且难以计算(看起来就像有一种模式,但它很快变得乏味且很难证明它将如何进展)。

对于最大输入,解决这个问题的好方法是什么?

2 个答案:

答案 0 :(得分:2)

我们可以使用矩阵求幂来得到对数解:

f(n) = C*f(n - 1) + f(n - 2)

a b       f(n)                    
     *            = [f(n + 1)   f(n)]
c d     f(n - 1)                        

这导致:

a = C
b = 1
c = 1
d = 0

因此,您可以使用此矩阵来获取函数的n个项。至于总和,请注意:

f(n)     = Cf(n - 1) + f(n - 2)
f(n - 1) = Cf(n - 2) + f(n - 3)
...
f(3)     = Cf(2)     + f(1)
=============================== +
s(n) - 2 = C(s(n - 1) - 1) + s(n - 2)
s(n) = Cs(n - 1) + s(n - 2) - (C - 2)

这不如你对Fibonacci数字所能做的那么好(用单个Fibonacci数表示总和),但它可以通过exponentiation by squaring使用类似的(3 x 3)来解决矩阵到初始重现之一,您可以使用相同的方法找到它,并且具有不同的起始条件:

s(1) = 1
s(2) = 2

答案 1 :(得分:0)

让我们尝试简化每一步的计算。首先,我们应该寻找a_n的非递归公式。这个Recurrence Relationship有一个封闭的表单解决方案,根据递归关系,我们a_n = A * r_1**n + B * r_2**n r_1r_2是等式r**2 = C * r + 1的解决方案在问题中。然后我们可以解析AB以便a_1 = a_2 = 1

现在,我们可以根据s_n的公式,并重新排列条款,考虑a_n

s_n = A * (r_1 + r_1**2 + ... + r_1**n) + B * (r_2 + r_2**2 + ... + r_2**n)

现在,使用Sum of a Geometric Progression的公式,我们得到公式

s_n = A * r_1 * (1 - r_1**n) / (1 - r_1) + B * r_2 * (1 - r_2**n) / (1 - r_2)

这为您提供了如何继续的基本概要。实际实施时需要考虑以下几点:

  1. 如果a_nr_1 = r_2的公式会发生变化。这不会发生在这个问题上。为什么呢?

  2. 如果r_1 = 1r_2 = 1,则公式要求除以0.

  3. 整数溢出。

  4. 最后的模数运算。