Algorithm 有效地计算序列2,2,4,2,4,6,2,4,6,8。。。在O(1)中

Algorithm 有效地计算序列2,2,4,2,4,6,2,4,6,8。。。在O(1)中,algorithm,math,Algorithm,Math,因此,对于某些输入,有一个问题给出了以下输出: 2,2,4,2,4,6,2,4,6,8,2,4,6,8,10,用于输入 n=1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 第一个最初的想法当然是使用DP来存储满足输入约束的答案(n=500000),然后从已生成的数组中检索答案 然而,看到上面的数字让我想到,这可能是一个可以用一些数学公式来回答的序列(通常是O(1),因此不必求助于DP(需要O(n)来生成,但是O(1)来检索).是否有一种方法,我可以制定一个公式来获得I-

因此,对于某些输入,有一个问题给出了以下输出:

2,2,4,2,4,6,2,4,6,8,2,4,6,8,10,
用于输入

n=1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,

第一个最初的想法当然是使用DP来存储满足输入约束的答案(
n=500000
),然后从已生成的数组中检索答案


然而,看到上面的数字让我想到,这可能是一个可以用一些数学公式来回答的序列(通常是
O(1)
,因此不必求助于DP(需要
O(n)
来生成,但是
O(1)
来检索).是否有一种方法,我可以制定一个公式来获得
I
-th元素的值,其中
I
是用户给出的输入?

我们可以将上述序列操作成一组序列,即:

2,2,4,2,4,6,2,4,6,8,…

进入

1,2,3,4,…
,此序列中的每个数字表示其组中成员的数量

这里的想法是将
i
-th元素分类为一个组。一旦我们找到了它的组,我们就可以从
i
中减去以前的组元素的数量,从而给出它相对于它自己的组的位置的精确位置(例如,上面序列中的第二个
4
是第三组的第二个元素)。我们知道元素的位置决定了它的值,也就是说,我们只需要将它的位置乘以2。这意味着,如果我们可以得到它在组中的相对位置,我们就可以找到它的值

例如,上面序列中的第一个
6
。它位于组3内,相对位置3,值为6。给定它在第一个序列中的位置(即位置6),我们如何计算它的值?我们可以在第二个序列上使用算术序列的公式(因为它是算术的)大致计算公式
Sn=n/2*(2a+(n-1))
上的
n
。在找出
n
值后,如果它不是一个整数,我们知道不可能
n
是向下舍入的值

计算上述序列中的第一个
6
,以找到其组:

Sn = n/2 * (2a + (n-1))
6 * 2 = n * (2 + n - 1)
12 = n^2 + n
0 = n^2 + n - 12
从那里,我们可以使用
n=(-b+sqrt(b^2-4ac)/2a)计算正的
n

我们将把这个
n
四舍五入到3,现在我们知道第一个
6
是组
3
。要找到它在组中的相对位置,我们只需从
i
中减去前面组中的元素数量。要找到前面组中的元素数量,我们可以使用相同的方法算术序列公式,尽管
n
3-1
(我们正在计算前一组中的成员数量)

知道在
i
-th元素之前有3个成员,我们可以从
i
(6)中减去
3
,得到3(它在其组中的相对位置)。然后,我们可以找到它的值my乘以2,从而得到6

C++中的代码:

int main() {
    int n;
    double approximateN;
    int S_approximateNMinusOne;

    cin >> n;
    approximateN = ceil((sqrt(1 + 4 * n * 2) - 1.00) / 2.00);
    S_approximateNMinusOne = (approximateN - 1) * (2 + approximateN - 2) / 2.00;
    cout << (n - S_approximateNMinusOne) * 2 << endl;

    return 0;
}
intmain(){
int n;
双重近似;
int S_近似为1;
cin>>n;
近似值=ceil((sqrt(1+4*n*2)-1.00)/2.00);
S_approxisenminusone=(approxisen-1)*(2+approxisen-2)/2.00;

这是OEIS中的2x序列。我希望找到一个O(1)不使用平方根,但没有运气的解决方案。不过,下次你必须找到序列的公式时,请从OEIS开始。@Dialogicus原谅我的无知,但你为什么要避免平方根?另外,当我试图找出另一个序列时,我偶然发现OEIS,但它似乎非常复杂,我被初始化了…工作使用浮点数的ng与错误联系在一起,不管它有多小。在某个值
n
时,这个sqrt数学会产生错误,但我们不知道提前到哪里。@Dialogicus:在许多编程语言中,您确实知道提前到哪里,
sqrt
函数将无法给出正确答案。我现在使用Python 3和我编写了一个
isqrt
函数,它使用Python的
sqrt
达到某个值(
2**50
)正确的地方。在该值以上,我使用一种较慢的方法,适用于所有整数值,甚至Python的扩展整数值。我确信这可以在其他语言中完成。好的,我已经更改了我的否决票。我知道在这个网站上很难做好自我回答问题。我最近考虑过自己做一个,但要求我提供反馈反馈说服我不要这么做——我改为编辑了一个老问题(来自其他人)并回答了这个问题。
S2 = 2/2 * (2 + 2 - 1)
S2 = 3
int main() {
    int n;
    double approximateN;
    int S_approximateNMinusOne;

    cin >> n;
    approximateN = ceil((sqrt(1 + 4 * n * 2) - 1.00) / 2.00);
    S_approximateNMinusOne = (approximateN - 1) * (2 + approximateN - 2) / 2.00;
    cout << (n - S_approximateNMinusOne) * 2 << endl;

    return 0;
}