给出参数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但是由于它很慢(我们仍然需要计算每个项的系数,这是最后的每个幂的循环)总和)并且难以计算(看起来就像有一种模式,但它很快变得乏味且很难证明它将如何进展)。
对于最大输入,解决这个问题的好方法是什么?
答案 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_1
和r_2
是等式r**2 = C * r + 1
的解决方案在问题中。然后我们可以解析A
和B
以便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)
这为您提供了如何继续的基本概要。实际实施时需要考虑以下几点:
如果a_n
,r_1 = r_2
的公式会发生变化。这不会发生在这个问题上。为什么呢?
如果r_1 = 1
或r_2 = 1
,则公式要求除以0.
整数溢出。
最后的模数运算。