Поиск решений для данной пары (количество факторов, число простых факторов) - PullRequest
0 голосов
/ 06 апреля 2020

Мне дали x и k, где x - это число факторов числа A, а k - это число простых факторов A. Учитывая x и k, я должен выяснить, существует ли такой A.

Например:

INPUT : 4 2 
OUTPUT : 1

Поскольку 6 - это число, имеющее 4 фактора 1 , 2, 3, 6 из которых 2 простые (2, 3). Также дается, что x и k могут иметь любые значения от 1 до 10 9 .

Вот мой код для этого:

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);

Где isprime(x) возвращает 1, если x простое, иначе 0.

Но при запуске программы выдается ошибка TLE. Может ли кто-нибудь помочь мне в оптимизации этого алгоритма, или, если существует какой-либо другой метод, можете ли вы просто объяснить мне это? Любая помощь в оптимизации этого алгоритма или использования другого метода будет любезна.

Ответы [ 3 ]

4 голосов
/ 06 апреля 2020

Let p 1 , p 2 , p 3 ,… p k - главные факторы некоторого натурального числа n . По основной теореме арифметики c, n можно представить в виде p 1 e 1 р 2 е 2 p 3 e 3 •… p k e k для некоторых натуральных чисел e 1 , e 2 , e 3 ,… e k . Кроме того, любой такой набор таких положительных целых чисел представляет собой одно положительное целое число таким образом.

Каждый фактор n может быть представлен как p 1 * * е одна тысяча девяносто шесть * ** 1098 одна тысяча девяносто семь * 1 р 2 * +1106 * е 2 p 3 f 3 •… p k f k для некоторых целых чисел f i , где 0 ≤ f i e i .

Каждый f i может иметь e i + 1 значения от 0 до e i , поэтому число факторов n равно ( е * ** одна тысяча сто семьдесят шесть 1177 * 1 + 1) • ( е 2 + 1) • ( е 3 * +1186 * +1) •… ( e k + 1).

с каждого e i должно быть положительным, каждое e i + 1 должно быть не менее 2. Теперь мы можем видеть что, если n имеет x множителей, то x выражается как произведение целых чисел k каждое по крайней мере на 2. И наоборот, если x выражается как произведение k целых чисел, каждое из которых не менее 2, этот продукт дает нам значения для e i , что дает нам положительное целое число n , которое имеет x факторов и k простых факторов.

Следовательно, число с x множителей и k простых множителей существует тогда и только тогда, когда x выражается как произведение k целых чисел, каждое по крайней мере на 2.

Чтобы проверить это, просто разделите x на простые числа, например, , разделите на 2 столько раз, сколько это возможно, без остатка, затем на 3, затем на 5 и т. Д. на. Как только x было разделено на k -1 факторов и результат больше 1, мы знаем, что x выражается как произведение k целых числа, по крайней мере, 2 (последний может быть составным, а не простым числом, таким как 2 • 3 • 3 • 3 • 35). Если x достигает 1 до или просто так, как мы разделили его на k -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));
}
0 голосов
/ 06 апреля 2020

Сначала ваша реализация слишком неэффективна

  • Не вызывайте функцию внутри для l oop, как это

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

    pow будет вызывается без необходимости на каждой итерации. Сохраните каждую константу в переменной до l oop. Но в этом случае просто используйте numbers < 1e9

  • Чтобы получить все множители n, вам просто нужно l oop до sqrt(n). Вы делаете for (long long int a = 1; a <= numbers && !stop; a++) { if (numbers % a == 0) {, например, вместо 10 4 петель для 10 8 вам понадобится 10 8 петель. Если numbers % a == 0, то a и numbers/a являются коэффициентами numbers

Но реальная проблема заключается в том, что ваш алгоритм имеет недостатки. Вы можете получить все факторы A, если знаете основные факторы A и их показатели. Если A = p 1 m p 2 n ... p k p тогда A будет иметь следующие факторы:

  • p 1 i для i = 1..m
  • p 2 i для i = 1..n
  • ...
  • p k i для i = 1..p
  • Факторы от 2 простых факторов: p 1 i p 2 j , p 1 i p 3 j , ... p 1 i p k j , p 2 i p 3 j , p 2 i p 4 j , ... p 2 i p k j , ... p k-1 i p k j
  • Факторы из 3 простых факторов ...
  • Факторы из k простых факторов

Это просто проблема подсчета комбинаций, которую можно легко решить, даже не зная A. Обратите внимание, что число факторы из кп Факторы имеют некоторое отношение к числу факторов из k-1 простых факторов

0 голосов
/ 06 апреля 2020

Ваш алгоритм очень неэффективен. Вот несколько идей:

  • отклонить очевидные ошибки: если x < 2 или k <= 0 или x < k, ответом будет 0 без дальнейшего тестирования.
  • не смешивать целочисленная арифметика с плавающей точкой. Используйте 1000000000 вместо pow(10, 9).
  • . Внутренний l oop может быть остановлен намного раньше, чем вы: запустите его, пока a * a < numbers, и добавьте 2 делителя для каждого совпадения. Добавьте еще один делитель, если a * a == numbers.
  • и остановите внутренний l oop, если noOfFactors > x или noOfPrimes > k.

Программа будет работать быстрее, но она все еще работает. не правильный подход, так как решение A может быть намного больше, чем диапазон целочисленных типов. Например, x = 1000, k = 1 имеет бесконечное число решений A = p 999 для любого простого числа p. Найти это решение с помощью перечисления невозможно.

Математический анализ проблемы: общее число факторов для числа A , которое имеет k простых факторов, составляет ( e 1 + 1) (e 2 + 1) ... (e k + 1) , где e i - это сила его i -го простого множителя, ie: A = Prod (p i e i ) .

Чтобы решение существовало, x должно быть результатом как минимум k факторов. Модифицированная версия факторинга l oop может определить, можно ли найти хотя бы k факторов, чье произведение равно x.

Вот простая программа, использующая этот подход, которая завершается, как только найдено 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;
}
...