最有效的方法是找到两个数字的公约数达到10 ^ 6

时间:2016-11-02 08:37:55

标签: c++ time-complexity factors

我想存储从1到10 ^ 6的所有数字的所有除数。但这似乎太慢了。这是我的代码的preprocess()函数:

for(int i=1; i<=1000000; i++)
{
    for(int j=1; j<=i/2; j++)
    {
        if(i%j==0)
            divi[i][j] = true;
    }
}

我使用了这样的地图容器:

  

map <int, bool> divi[1000010];

然后我试图找到两个给定数字的公约数。

preprocess();

int T, A, B;

cin >> T;

while(T--)
{
    cin >> A >> B;

    int common = 0;
    for(it = divi[A].begin(); it!=divi[A].end(); it++)
    {
        if(divi[B][it->first]==true)
            common++;
    }

    cout << common << endl;

我现在该如何处理以使其足够快?

2 个答案:

答案 0 :(得分:4)

除了使用std::map本身很昂贵(不能使用数组吗?)这一事实之外,快速的数字胜利只能达到数字的平方根。内循环。

for (int j = 1; j * j <= i; j++)

(注意平方j比计算i的平方根要便宜,并让你远离浮点计算。)

必须注意,如果j是除数,则i / j 除数。所以你还需要替​​换

divi[i][j] = true;

divi[i][j] = divi[i][i / j] = true;

此优化以计算数的除数为中心。有更快的方法来获取 set 数字的除数,但我的方法可能就足够了。如果不是,请关注。

答案 1 :(得分:1)

这取决于你想要什么:如果你只想要一些特定数字的公约数,那么欧几里得算法就是解决方案。

如果你真的想要一个所有数字1..n的所有除数的列表,一个解决方案就是(类似于Sieve):

  for(int I=1;I<=sqrt(n);++I) {
     for(int j=I;j*I<=n;++j) divi[I*j][j]=divi[I*j][I]=true;
  }

原始代码的代码复杂度为O(N ^ 2),第一个答案为O(N ^ 1.5)。我相信新公式是O(N * log N)