数学 - 公式v [i] =([V [i-1] * v [i-1] /(i 2)] v [i-1] * i

Math - Formula V[i] = ([ V[i-1] * V[i-1] / (i + 2)] + V[ i-1] * i + i + 1) % 666013

本文关键字:i-1 公式 数学      更新时间:2023-10-16

我需要一些帮助来分辨此公式:

v [i] =([v [i-1] * v [i-1]/(i 2)] v [i-1] * i i 1)%666013 其中v [0] = 3和示例:v [10000000] = 22230

我的解决方案是:

#include <iostream>
#include <algorithm>
#include <cmath>
#include <fstream>
using namespace std;
ifstream fin ("smen.in");
ofstream fout ("smen.out");
unsigned long long int n, k;
int mod = 666013;
int numereus(int n)
{
    if (n > 0)
    {
        k = numereus(n-1) % mod;
        return ((((((((k*k)% mod)/((n%mod+2) % mod))%mod)+(k*(n%mod))% mod)% mod) + (n % mod)) % mod + 1) % mod;
    }
    else
    {
        return 3;
    }
}
int main()
{
    cin >> n;
    cout << numereus(n);
    return 0 ;
}

我的C 解决方案对数字无效> 25000

递归解决方案在那些快速移动到基本情况的情况下最好。

例如,二进制搜索将摆脱每次复发的一半解决方案空间,以便您可以在大约32个递归中搜索40亿个项目。

您的算法处理25,000个项目需要25,000个堆栈框架,因此可能更适合迭代解决方案。堆栈不是无限的资源。

在实施迭代解决方案方面,请参见以下伪代码,该伪代码应该给您一个想法:

def fn(n):
    rv = 3
    i = 0
    while n > 0:
        i = i + 1
        rv = (rv * rv / (i + 2) + rv * i + i + 1) % 666013
        n = n - 1
    return rv

这是python中的概念验证,看起来与上面的代码非常相似,因为说实话,如果您放弃所有lambda/closure/list comperhension的内容,python可以使完美的伪代码语言: - )

def fn(n):
    rv = 3
    i = 0
    while n > 0:
        i = i + 1
        rv = (rv * rv / (i + 2) + rv * i + i + 1) % 666013
        n = n - 1
    return rv
print fn(0)
print fn(1)
print fn(2)
print fn(10000000)

此输出:

3
8
35
22230

根据您的问题,最后一个似乎是10,000,000的正确值。


等效的C 代码将沿着:

的线
#include <iostream>
int numereus (int n) {
    unsigned long long int rv = 3;
    int i = 0;
    while (n-- > 0) {
        i = i + 1;
        rv = (rv * rv / (i + 2) + rv * i + i + 1) % 666013;
    }
    return rv;
}
int main (void) {
    std::cout
        << numereus(0) << 'n'
        << numereus(1) << 'n'
        << numereus(2) << 'n'
        << numereus(10000000) << 'n';
    return 0 ;
}

保持现有代码的廉价方法是使用备忘录。您的代码很容易在循环中编写,在这种情况下,这可能是您的首选方法,但是备忘很高兴知道。

这个想法是将昂贵计算的结果存储在缓存中,然后将其检索以节省时间(或资源)。

在您的代码情况下,每次numereus都称为将其答案存储在数组中。如果以后调用numereus,则使用相同的参数调用,它检查了它是否在数组中有答案,如果是的,则在不进行进一步递归或计算的情况下返回答案。

要回答您的问题,我们可以反复调用numereus,其值越来越大,以构建缓存。这样可以防止堆栈溢出的可能性,并且仍然可以在O(N)时间内工作,因为每个呼叫numereus(i)都能获得numereus(i-1)的加速值。

授予,您将燃烧大量的记忆构建这么大的缓存。解决此问题的一种方法是仅缓存每个Xth值。例如,您只能缓存来自偶数数字的输入。这将您需要的存储空间量减少了一半,同时将递归深度加倍。

在您的问题中,以下未经测试的代码可以起作用:

#include <iostream>
#include <algorithm>
#include <cmath>
#include <fstream>
#include <vector>
using namespace std;
ifstream fin ("smen.in");
ofstream fout ("smen.out");
unsigned long long int n, k;
int mod = 666013;
int numereus(std::vector<int> &memoized, int n){
    if(memoized[n]!=-1)
        return memoized[n];
    if (n > 0){
        k = numereus(memoized,n-1) % mod;
        return memoized[n]=((((((((k*k)% mod)/((n%mod+2) % mod))%mod)+(k*(n%mod))% mod)% mod) + (n % mod)) % mod + 1) % mod;
    } else {
        return 3;
    }
}
int main()
{
    std::vector<int> memoized(10000000);
    //I use -1 as a place holder here. Just make sure this is a value your function can never produce
    std::fill(memoized.begin(),memoized.end(),-1);
    cin >> n;
    for(int i=0;i<n;i++) //Build table of answers
      numereus(memoized,i);
    cout << numereus(memoized,n);
    return 0 ;
}