【问题标题】:Most efficient way to find the common divisors of two numbers upto 10^6找到两个数字的公约数的最有效方法,最多为 10^6
【发布时间】:2016-11-02 08:37:55
【问题描述】:

我想存储从 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 &lt;int, bool&gt; 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;

我现在应该如何接近以使其足够快?

【问题讨论】:

  • 请注意,divi[B][it-&gt;first] == true 将创建一个新的映射条目(如果不存在)。这会变得非常昂贵,尤其是对于素数。
  • 顺便说一句,std::map &lt;int, bool&gt; 可能会被 std::set&lt;int&gt; 替换。
  • 通过使用 sieve 方法,您可以摆脱预处理器方法中的模和除法。
  • 筛法的主要优点是不用检查所有元素,模和除法几乎和乘法一样快。

标签: c++ time-complexity factors


【解决方案1】:

除了使用 std::map 本身会很昂贵(你不能使用数组吗?)之外,快速的数字胜利是只上升到内部循环中数字的平方根。

for (int j = 1; j * j &lt;= i; j++)

(注意对j 求平方比计算i 的平方根更便宜,并且让您远离浮点计算。)

这必须同时注意如果j 是一个除数,那么i / j 也是一个除数。所以你也需要更换

divi[i][j] = true;

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

此优化以单个数的除数计算为中心。有更快的方法来获取一组 数字的除数,但我的方法可能就足够了。如果没有,请投反对票。

【讨论】:

    【解决方案2】:

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

    如果您真的想要所有数字 1..n 的所有除数的列表,一种解决方案是(类似于筛子):

      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)

    【讨论】:

    • 当然你也可以用 I*I
    猜你喜欢
    • 1970-01-01
    • 2012-03-01
    • 1970-01-01
    • 2020-04-17
    • 1970-01-01
    • 1970-01-01
    • 2020-12-07
    • 2021-04-05
    • 2011-03-10
    相关资源
    最近更新 更多