【问题标题】:Finding solutions for a given pair (number of factors, number of prime factors)寻找给定对的解决方案(因子的数量,素因子的数量)
【发布时间】:2020-04-06 06:33:40
【问题描述】:

我得到了xk,其中x 是数字A 的因数个数,kA 的质因数数。给定xk,我必须找出这样的A是否存在。

例如:

INPUT : 4 2 
OUTPUT : 1

因为 6 是一个有 4 个因数 1、2、3、6 的数,其中 2 个是素数 (2, 3)。 此外,xk 可以有 1 到 109 之间的任何值。

这是我的代码:

long long int x, k;
scanf("%lld%lld", &x, &k);

int ans = 0;

bool stop = false;

for (long long int numbers = 1; numbers < pow(10, 9) && !stop; numbers++) {
    long long int noOfFactors = 0, noOfPrimes = 0;
    for (long long int a = 1; a <= numbers && !stop; a++) {
        if (numbers % a == 0) {
            noOfFactors += 1;
            if ((isprime(a)) == 1) {
                noOfPrimes += 1;
            }
         }
     }
     if (noOfFactors == x && noOfPrimes == k) {
         ans = 1;
         stop = true;
     } else
         ans = 0;
}   
printf("%d\n", ans);

如果 x 是素数,isprime(x) 返回 1,否则返回 0。

但在运行程序时,它显示 TLE 错误。 谁能帮我优化这个算法,或者如果存在任何其他方法,你能解释一下吗? 对于优化此算法或使用其他方法的任何帮助,我们将不胜感激。

【问题讨论】:

  • 接下来,您不断地重新计算停止条件pow(10, 9),您可以将其放入变量中。
  • 你做错了。给定k(主要因素的数量),您可以开始计算可能的x(所有因素的数量)的集合。不需要从号码开始,需要从k开始。甚至哪个素数都没有关系。
  • 你能贴出原始问题的链接吗?
  • 这个问题来自正在进行的 codeChef 竞赛
  • 这个问题是正在进行的 Codechef April Long Challenge 2020 的一部分。问题链接:[问题][1] 因此,不应直接在此门户中提问。这违反了 Codechef 行为准则和用户可能会被 Codechef 禁止。今后,请避免在正在进行的编码挑战中提问。

标签: c algorithm primes factors largenumber


【解决方案1】:

p1, p2, p3 , … pk 是某个正整数 n 的质因数。通过fundamental theorem of arithmeticn可以表示为p1e1p2e2p3e3• … pkek对于一些正整数e 1, e2, e3, ... ek。此外,任何这样的一组这样的正整数都以这种方式表示一个正整数。

n的每一个因子都可以表示为p1f1p2f2p3f3• … pkfk 对于一些整数 fi 其中 0 ≤ fiei.

每个fi可以有ei sub>+1 个值从 0 到 ei,所以 n 的因子个数为 (e1+1)•(e2+1)•(e3+1)• … (ek+1)。

由于每个 ei 必须是正数,因此每个 ei em>+1 必须至少为 2。现在我们可以看到,如果 nx 个因子,那么 x 是可表示为 k 个至少为 2 的整数的乘积。相反,如果 x 可表示为 k 个至少为 2 的整数的乘积,该产品为我们提供了 ei 的值,它为我们提供了一个具有 x 的正整数 n 个因数和 k 个质因数。

因此,当且仅当 x 可表示为 的乘积时,存在具有 x 个因数和 k 个质因数的数k 个整数,每个至少为 2。

要对此进行测试,只需将 x 除以素数,例如,尽可能多次除以 2,然后除以 3,再除以 5,等等。一旦 x 除以 k-1 个因子并且结果大于 1,那么我们知道 x 可以表示为 k 的乘积em>k 个整数,每个整数至少为 2(最后一个可能是合数而不是素数,例如 2•3•3•3•35)。如果 x 在我们将其除以 k-1 个因子之前或刚刚达到 1,则不存在这样的数字。

附录

进一步考虑,在测试 x 的因子时,没有必要使用素数作为候选。我们可以简单地遍历整数,测试每个候选 f 是否是 x 的因子。尝试通过首先测试 f 是否为素数来过滤这些将比简单地测试 f 是否是 x 的因子要花费更多的时间。 (这并不是说测试 x 的素数因子的更复杂的方法,例如使用准备好的许多素数表不会更快。)所以下面的代码就足够了。

#include <stdint.h>


/*  Return true if and only if there exists a positive integer A with exactly
    x factors and exactly k prime factors.
*/
static _Bool DoesAExist(uintmax_t x, uintmax_t k)
{
    /*  The only positive integer with no prime factors is 1.  1 has exactly
        one factor.  So, if A must have no prime factors (k is zero), then an A
        exists if and only if x is one.
    */
    if (k == 0) return x == 1;

    /*  A number with exactly one prime factor (say p) has at least two factors
        (1 and p) and can have any greater number of factors (p^2, p^3,...).
        So, if k is one, then an A exists if and only if x is greater than one.
    */
    if (k == 1) return 1 < x;

    /*  Otherwise, an A exists only if x can be expressed as the product of
        exactly k factors greater than 1.  Test this by dividing x by factors
        greater than 1 until either we have divided by k-1 factors (so one
        more is needed) or we run out of possible factors.

        We start testing factors with two (f = 2).

        If we find k factors of x during the loop, we return true.

        Otherwise, we continue as long as there might be more factors.  (When
        f*f <= x is false, we have tested the current value of x by every
        integer from two to the square root of x.  Then x cannot have any more
        factors less than x, because if there is any factorization x = r*s,
        either r or s must be less than or equal to the square root of x.)

        For each f, as long as it is a factor of the current value of x and we
        need more factors, we divide x by it and decrement k to track the
        number of factors still required.
    */
    for (uintmax_t f = 2; f*f <= x; ++f)
        while (x % f == 0)
        {
            /*  As long as f is a factor of x, remove it from x and decrement
                the count of factors still needed.  If that number reaches one,
                then:

                    If the current value of x exceeds one, it serves as the
                    last factor, and an A exists, so we return true.

                    If the current value of x exceeds one, there is no
                    additional factor, but we still need one, so no A exists,
                    so we return false.
            */
            x /= f;
            if (--k <= 1) return 1 < x;
        }

    /*  At this point, we need k more factors for x, and k is greater than one
        but x is one or prime, so x does not have enough factors.  So no A with
        the required properties exists, and we return false.
    */
    return 0;
}


#include <stdio.h>


int main(void)
{
    printf("False test cases:\n");
    printf("%d\n", DoesAExist(0, 0));   //  False since each positive integer has at least one factor (1).
    printf("%d\n", DoesAExist(2, 0));   //  False since no number has two factors and no prime factors.

    printf("%d\n", DoesAExist(0, 1));   //  False since each positive integer has at least one factor (1).
    printf("%d\n", DoesAExist(1, 1));   //  False since each positive integer with a prime factor has at least two factors (one and the prime).
    printf("%d\n", DoesAExist(2, 2));   //  False since each number with two prime factors (p and q) has at least four factors (1, p, q, and pq).
    printf("%d\n", DoesAExist(3, 2));   //  False since each number with two prime factors (p and q) has at least four factors (1, p, q, and pq).

    printf("%d\n", DoesAExist(8, 4));

    printf("%d\n", DoesAExist(6, 3));
    printf("%d\n", DoesAExist(22, 3));

    printf("%d\n", DoesAExist(24, 5));
    printf("%d\n", DoesAExist(88, 5));
    printf("%d\n", DoesAExist(18, 4));
    printf("%d\n", DoesAExist(54, 5));
    printf("%d\n", DoesAExist(242, 4));
    printf("%d\n", DoesAExist(2662, 5));

    printf("True test cases:\n");
    printf("%d\n", DoesAExist(1, 0));   //  True since 1 has one factor and zero prime factors.
    printf("%d\n", DoesAExist(2, 1));   //  True since each prime has two factors.
    printf("%d\n", DoesAExist(3, 1));   //  True since each square of a prime has three factors.
    printf("%d\n", DoesAExist(4, 1));   //  True since each cube of a prime has three factors.
    printf("%d\n", DoesAExist(4, 2));   //  True since each number that is the product of two primes (p and q) has four factors (1, p, q, and pq).

    printf("%d\n", DoesAExist(8, 2));
    printf("%d\n", DoesAExist(8, 3));

    printf("%d\n", DoesAExist(6, 2));
    printf("%d\n", DoesAExist(22, 2));

    printf("%d\n", DoesAExist(24, 2));
    printf("%d\n", DoesAExist(24, 3));
    printf("%d\n", DoesAExist(24, 4));
    printf("%d\n", DoesAExist(88, 2));
    printf("%d\n", DoesAExist(88, 3));
    printf("%d\n", DoesAExist(88, 4));
    printf("%d\n", DoesAExist(18, 2));
    printf("%d\n", DoesAExist(18, 3));
    printf("%d\n", DoesAExist(54, 2));
    printf("%d\n", DoesAExist(54, 3));
    printf("%d\n", DoesAExist(54, 4));
    printf("%d\n", DoesAExist(242, 2));
    printf("%d\n", DoesAExist(242, 3));
    printf("%d\n", DoesAExist(2662, 2));
    printf("%d\n", DoesAExist(2662, 3));
    printf("%d\n", DoesAExist(2662, 4));
}

【讨论】:

  • 非常感谢您的回答。我理解了这个方法,但我无法实现它。我的方法仍然需要很多时间。非常感谢任何有关如何实施它的帮助。
【解决方案2】:

首先你的实现效率太低了

  • 不要像这样在 for 循环中调用函数

    for (long long int numbers = 1; numbers < pow(10, 9) && !stop; numbers++)
    

    pow 将在每次迭代中被不必要地调用。在循环之前将每个常量保存到变量中。但在这种情况下,只需使用numbers &lt; 1e9

  • 要获取n 的所有因子,您只需循环到sqrt(n)。你正在做for (long long int a = 1; a &lt;= numbers &amp;&amp; !stop; a++) { if (numbers % a == 0) {,例如,你需要 108 循环而不是 108 的 104 循环。如果numbers % a == 0anumbers/a 都是numbers 的因数

但这里真正的问题是您的算法有缺陷。如果您知道A 的质因数及其指数,则可以得到A 的所有因数。如果 A = p1m p2n ... pkp 那么A会有以下因素:

  • p1i for i = 1..m
  • p2i for i = 1..n
  • ...
  • pki for i = 1..p
  • 来自 2 个主要因数的因数:p1ip2j, p1ip3j,... p1ip kj, p2ip3j, p2ip4j,... p2ipkj,... pk-1ipkj
  • 来自 3 个主要因数的因数...
  • k 质因数中的因数

这纯粹是一个组合计数问题,甚至可以在不知道 A 的情况下轻松完成。请注意,k 个素数因子的因子数与 k-1 个素数因子的因子数有一定关系

【讨论】:

    【解决方案3】:

    您的算法非常效率低下。以下是一些想法:

    • 拒绝明显失败:如果x &lt; 2k &lt;= 0x &lt; k 答案是0,无需进一步测试。
    • 不要混合使用浮点和整数运算。使用1000000000 而不是pow(10, 9)
    • 内部循环可以比你更早地停止:仅在a * a &lt; numbers 时运行它,并为每个匹配添加 2 个除数。如果a * a == numbers,则添加另一个除数。
    • 如果noOfFactors &gt; xnoOfPrimes &gt; k 也停止内部循环。

    程序会运行得更快,但它仍然不是正确的方法,因为解决方案A 可能比整数类型的范围大得多。例如x = 1000, k = 1 对于任何素数 p 有无限数量的解 A = p999。通过枚举找到这个解决方案是不可能的。

    用数学方法分析问题:具有 k 个质因数的数 A 的因数总数为 (e1 +1)(e2+1)...(ek+1),其中ei 是它的第 i 个素因数的幂,即:A = Prod(piei子>).

    要存在解决方案,x 必须至少是 k 因子的乘积。因子循环的修改版本可以确定是否至少可以找到乘积等于x 的因子k

    这是一个使用这种方法的简单程序,一旦找到k 因子就完成:

    #include <stdio.h>
    
    int test(unsigned int x, unsigned int k) {
        if (k == 0) {
            /* k is not supposed to be 0, but there is a single number A
               with no prime factors and a single factor: A = 1 */
            return x == 1;
        }
        if (x > k && k > 1) {
            for (unsigned int p = 2; x / p >= p;) {
                if (x % p == 0) {
                    x /= p;
                    if (--k == 1)
                        break;
                } else {
                    /* skip to the next odd divisor */
                    p += 1 + (p & 1);
                }
            }
        }
        return k == 1 && x > 1;
    }
    
    int main() {
        unsigned int x, k;
    
        while (scanf("%u%u", &x, &k) == 2)
            printf("%d\n", test(x, k));
    
        return 0;
    }
    

    【讨论】:

    • 请避免为在线编码挑战提供代码解决方案,因为这可能会影响参与其中的参赛者的排名。
    • 复制网上找的代码很常见。其他参赛者也这样做。这里的目标是教程序员新技能,让他们对新方法感到好奇......如果他们只是在不理解的情况下复制,他们将无济于事。如果您对真正的挑战感兴趣,请尝试projecteuler.net。每当你解决了一个问题,你就可以看到其他人的代码,这种体验是多么的谦卑。
    • 同意,但我担心的是在比赛结束后为他们启用代码,因为比赛有一些规则,它妨碍了其他努力解决问题的人的评价。谢谢跨度>
    • @ChandraShekhar:我明白,但你没有投票结束这个问题。您是否至少为版主标记了它?比赛现在已经结束,所以我将保留这个答案。有多少参赛者使用了这种方法?有多少人使用了这个确切的代码?你会惩罚他们吗?
    • 也许 Codechef 会。因为他们有一个内部算法。我也标记了这个问题并将其标记为评论。
    猜你喜欢
    • 2020-11-19
    • 1970-01-01
    • 1970-01-01
    • 2012-01-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-24
    • 1970-01-01
    相关资源
    最近更新 更多