【问题标题】:PROJECT EULER #29欧拉计划 #29
【发布时间】:2010-01-27 14:41:16
【问题描述】:

好吧,在用天真的 STL 集解决了这个problem 之后,我正在阅读论坛条目,在那里我找到了这个条目:

 #include <iostream>   
 #include <cmath> 
 #define MAX 100
 using namespace std;

 int main(){
    int res=(MAX-1)*(MAX-1);
    for(int i=2;i<MAX;i++)
        for(int j=i*i;j<=MAX;j=j*i)
            res = res-int(MAX*(log(i)/log(j)))+1;
     cout<<res<<endl;
     return 0;
  }

作者的解释: Maximum will be 99*99. I subtracted occurrences of those numbers which are powers of some lower numbers (2-100): - For example: - 4^2,4^3,4^4 (i.e. 3 should be subtracted) as they will be duplicates from lower number powers as in 2^4,2^6,2^8

这个程序给出了正确的答案check here,但我无法得到实现的逻辑,确切地说我没有得到如何确定重复项。有人可以帮忙吗?

【问题讨论】:

  • static const int Max = 100; 会更好。 C++ 程序员使用#define 的常量,tsk tsk。
  • 那不是我,我只是引用了作者的话:P
  • 这个算法不起作用。尝试 MAX = 8 或 9。对于 8,它应该给出 44,但给出 45。对于 9,它应该给出 54,但给出 56。

标签: c++ algorithm math


【解决方案1】:

我可能遗漏了一些东西,但在我看来,这个程序给出了错误的答案。差一分了如果我将MAX 设置为 10,它会减少 2。

我读到一些玩家喜欢生成近似答案,然后对 Project Euler 服务器进行字典攻击以暴力破解问题。其他玩家则认为这与事情的精神背道而驰。

无论如何——这样的算法(从 N*M 开始并消除重复项)是解决问题的正确方法,但正如我所写的那样,这段代码对我来说没有多大意义。请注意,无论如何int(MAX*(log(i)/log(j))) 对舍入误差非常敏感;但即使你通过使用整数运算消除了错误的来源,程序仍然给出错误的答案。

编辑:我们如何(正确)计算重复项?

首先你必须明白,只有当它们具有相同的素数分解时,它们才相同。所以只会有重复 a1b1 = a2b2a1 a2 是同一整数的不同整数幂,我将其称为 x。例如,

  • 97 = 314;这是可能的,因为 9 和 3 都是 3 的幂。
  • 86 = 49;这是可能的,因为 8 和 4 都是 2 的幂。

所以我们已经确定对于所有重复,a1 = xe1a2 = xe 2 对于一些整数 xe1e 1.

然后用一点代数,

a1b1 = a2b2

xe1b1 = xe2b2

e1b1 = e2子>b2

回到前面的例子,

  • 97 = 314 因为 2×7 = 1×14。
  • 86 = 49 因为 3×6 = 2×9。

因此,要查找任何给定 x 的所有重复项,您只需要查找更简单的表达式 eb 的重复项,其中 2 ≤ xe ≤ 100 和 2 ≤ b ≤ 100。

这是一个更简单问题的图片,x=3 和 b 的范围仅从 2 到 10。我标记了两个重复的地方。

e=1  a=3    *********
e=2  a=9      * * * * * * * * *
e=3  a=27       *  *  *  *  *  *  *  *  *
e=4  a=81         *   *   *   *   *   *   *   *   *
                  |               |
        1*8 = 2*4 =  4*2         3*8 = 4*6
        3^8 = 9^4 = 81^2        27^8 = 81^6

这里是重复的:

e=1  a=3    *********
e=2  a=9      x x x x * * * * *
e=3  a=27       x  x  x  *  x  *  *  *  *
e=4  a=81         x   x   x   x   x   *   *   *   *

您发现的 C++ 程序试图通过访问每对重叠的行 i 和 j 来计算它们,并计算行 i 与行 j 重叠的数量。但同样,除非我遗漏了什么,否则该程序似乎非常不精确。而且它完全遗漏了一些行对(你永远不会有 i=9 和 j=27,或者 i=27 和 j=81)。

【讨论】:

  • 您能解释一下重复项是如何计算的吗?
  • 代码给出了正确的答案,检查一下:ideone.com/Kcuc2BGu
  • nthrgeek:它在我的机器上给出了 9182。我已经更新了帖子,详细解释了我认为该程序试图做什么以及它出错的一个原因。
  • 如果消除舍入误差,它会产生 9182,即减一。 ideone.com/WSXVJEOD
  • 我一直在努力解决这个问题,试图实现相同的方法,直到我看到你的解释。谢谢。
【解决方案2】:

首先,它在第6行将res设置为99*99,因为MAX被定义为100。然后它进入一个循环,条件是i小于MAX。然后它进入这个伪代码循环

int i;
int j;
int x=2;

for( j = i2; j x)
{
res = res- (MAX* ( jlog(i) )+1;
x++;
}

对不起,上面没有使用&lt;pre&gt;&lt;code&gt;;但如果我这样做了,我将无法使用&lt;sup&gt;

请注意log(a)/log(x)xlog(a)

相同

因为&lt;sup&gt; 在那里不起作用,所以提出问题:

2log(2) = 1 因为 21 = 2
2log(4) = 2 因为 22 = 2
日志(x) == 10日志(x)
日志(10) = 1

glog(x) = y => gy = x

【讨论】:

  • b^a 的反面。 b 是地面。当离开时,假设地面为 10:因此 10log(10) 将返回 1,因为 10^1 = 10,并且 2log(2) 将返回 1,因为 2^1 = 2 和 2log(4) 将返回 2,因为2^2 = 4
  • 抱歉不能在评论区使用html,所以不能上标
  • 好吧,我放弃了。我知道他在做什么,但为什么在我头上。对不起nthrgeek
  • 嘿别那么轻易放弃.. :)
【解决方案3】:

嗯,问题涉及组合从一个范围中选择的两个数字的方法。有 99 个可能的数字,所以组合的数量是 99 * 99,可能有重复。他这里的基本算法是找出存在多少重复项,然后从最大值中减去该值。

至于计算重复项,根据主要因素来直观地考虑数字可能会有所帮助。将数字提高到整数幂意味着将其与自身相乘;因此,表示为素数列表,这相当于简单地连接列表。例如,6 是 {2, 3},所以 6^3 将是 {2, 2, 2, 3, 3, 3}。请注意,如果您计算每个素数在列表中出现的次数,x^n 将始终与 x 具有 相同的比例,例如 6^n 将具有相同数量的 2 和 3。因此,范围内任何两个素数比例相同的数都必须是某个数的幂。

因此,在完整列表中,每个不同比例的素数将重复出现 x^2, x^3, x^4..., (x^3)^2, (x^3)^4 ...、(x^4)^2... 等,其中 x 是具有该比例的最小数;更准确地说,(x^m)^n 其中 (x^m) n),因此计数重复等于计算 x^(mn) 也可以

【讨论】:

    【解决方案4】:

    有(至少)两种方法可以解决这个问题。一种是从 0 开始计算不同值,并为每个以前未见过的计算值添加一个。另一种方法是计算值的最大个数,然后每重复一个就减去一个。

    发帖人正在尝试第二种方法。对于 99 个值,a 的范围可以从 2 到 100,b 也可以,因此产生了 99 * 99 个值。然后,发帖人尝试减去重复值以获得正确答案。

    编辑:但是,发帖人写了一个不正确的算法。 例如,设置MAX = 89。对于8,它应该给44,但它给45。对于9,它应该给出54,但给出56。要么他们运气好,遇到了一个算法,它为某些输入提供了正确的答案,要么他们逆向设计了一个在 MAX = 100 时有效但不适用于所有其他值的算法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多