Найдите сумму наименьших общих кратных всех подмножеств данного множества

Дано: установить A = {a0, a1, ..., aN-1} (1 ≤ N ≤ 100) с 2 ≤ ai ≤ 500.

Вопрос: найти сумму всех наименьших общих кратных (НОК) всех подмножеств A размера не менее 2.

LCM набораB = {b0, b1, ..., bk-1} определяется как минимальное целое число Bmin такое, что bi | Bmin для всех 0 ≤ i < k.

Пример:

Пусть N = 3 и A = {2, 6, 7}, тогда:

LCM({2, 6})      =    6
LCM({2, 7})      =   14
LCM({6, 7})      =   42
LCM({2, 6, 7})   =   42
----------------------- +
answer              104

Наивным подходом было бы простое вычисление LCM для всех O(2N) подмножеств, что невозможно для достаточно больших N.


Эскиз решения:

Задача получена на конкурсе*, который также предоставил схема решения. Вот где возникает моя проблема: я не понимаю намека на подход.

Решение гласит (по модулю некоторых небольших исправлений грамматики):

Решение немного сложное. Если мы внимательно посмотрим, то увидим, что целые числа находятся между 2 и 500. Итак, если мы разложим числа на простые множители, мы получим следующие максимальные степени:

 2 8  
 3 5
 5 3
 7 3
11 2
13 2
17 2
19 2

Кроме этого, все простые числа имеют степень 1. Таким образом, мы можем легко вычислить все возможные состояния, используя эти целые числа, оставив 9 * 6 * 4 * 4 * 3 * 3 * 3 * 3 состояний, что составляет почти 70000. Для других целых чисел мы можем сделать dp следующим образом: dp[70000][i], где i может быть от 0 до 100. Однако, поскольку dp[i] зависит от dp[i-1], dp[70000][2] достаточно. Это оставляет сложность n * 70000, что возможно.

У меня следующие конкретные вопросы:

  • Что подразумевается под этими состояниями?
  • Означает ли dp динамическое программирование, и если да, то какое рекуррентное соотношение решается?
  • Как dp[i] вычисляется из dp[i-1]?
  • Почему большие простые числа не влияют на количество состояний? Каждое из них встречается 0 или 1 раз. Не следует ли умножать количество состояний на 2 для каждого из этих простых чисел (что снова приводит к недопустимому пространству состояний)?

*Исходное описание проблемы можно найти на сайте этот источник (проблема F). Этот вопрос является упрощенной версией этого описания.


person MasterMind    schedule 20.10.2014    source источник
comment
@PhamTrung, что означает состояние, что означает dp[state][i] и как сделать перевод dp[f(state)][i] = g( dp[state][i-1] )   -  person Ralor    schedule 21.10.2014
comment
@MasterMind Я чувствую ваше разочарование по поводу этой проблемы, поскольку она также застряла у меня в голове с тех пор, как я прочитал ваш вопрос :) Я попытался немного перефразировать вопрос, чтобы (надеюсь) получить больше ответов. Я думаю, что максимально приблизился к сути вашего первоначального вопроса, но не могли бы вы проверить это?   -  person Vincent van der Weele    schedule 22.10.2014
comment
@VincentvanderWeele Большое спасибо, вы буквально полностью меня понимаете. Модификация, которую вы сделали, просто потрясающая, вопросы, которые вы задали, являются ключевыми и сутью проблемы. Еще раз, спасибо   -  person MasterMind    schedule 23.10.2014
comment
Stack Overflow — это не сайт, на котором люди просят сделать вашу домашнюю работу...   -  person Rob Baillie    schedule 12.11.2014


Ответы (4)


Обсуждение

После прочтения фактического описания конкурса (страница 10 или 11) и набросок решения, я должен заключить, что автор наброска решения довольно неточен в своем письме.

Проблема высокого уровня заключается в вычислении ожидаемого срока службы, если компоненты выбираются случайным образом путем честного подбрасывания монеты. Это то, что приводит к вычислению LCM всех подмножеств — все подмножества эффективно представляют пространство выборки. Вы можете получить любой возможный набор компонентов. Время отказа устройства зависит от LCM комплекта. Таким образом, ожидаемый срок службы представляет собой среднее значение LCM всех комплектов.

Обратите внимание, что это должно включать LCM наборов только с одним элементом (в этом случае мы предполагаем, что LCM является самим элементом). Набросок решения кажется саботажным, возможно, потому, что они обработали его менее элегантно.

Что подразумевается под этими состояниями?

Автор скетча использует слово состояние только дважды, но, видимо, умудряется менять значения. При первом использовании слова состояние кажется, что они говорят о возможном выборе компонентов. Во втором случае они, вероятно, говорят о возможном времени отказа. Они могли запутать эту терминологию, потому что их решение для динамического программирования инициализирует значения из одного использования слова, а рекуррентное отношение вытекает из другого.

Означает ли dp динамическое программирование?

Я бы сказал, что либо так, либо это совпадение, поскольку набросок решения, похоже, в значительной степени подразумевает динамическое программирование.

Если да, то какое рекуррентное соотношение решается? Как dp[i] вычисляется из dp[i-1]?

Все, что я могу предположить, это то, что в их решении состояние i представляет время до отказа , T(i), с количеством подсчетов времени до отказа, dp[i]. Полученная сумма будет суммировать все dp[i] * T(i).

Тогда dp[i][0] будет временем отказа, учитываемым только для первого компонента. Тогда dp[i][1] будет временем отказа, подсчитанным для первого и второго компонента. dp[i][2] будет для первого, второго и третьего. И т.д..

Инициализируйте dp[i][0] нулями, за исключением dp[T(c)][0] (где c — первый рассматриваемый компонент), который должен быть равен 1 (поскольку время отказа этого компонента уже подсчитано один раз).

Чтобы заполнить dp[i][n] из dp[i][n-1] для каждого компонента c:

  • Для каждого i скопируйте dp[i][n-1] в dp[i][n].
  • Добавьте 1 к dp[T(c)][n].
  • Для каждого i добавьте dp[i][n-1] к dp[LCM(T(i), T(c))][n].

Что это делает? Предположим, вы знали, что у вас есть время до отказа j, но вы добавили компонент со временем до отказа k. Независимо от того, какие компоненты у вас были раньше, ваше новое время для отказа — LCM(j, k). Это следует из того, что для двух наборов A и B, LCM(A union B} = LCM(LCM(A), LCM(B)).

Точно так же, если мы рассматриваем время до отказа T(i) и время до отказа нашего нового компонента T(c), результирующее время до отказа составляет LCM(T(i), T(c)). Обратите внимание, что мы записали это время до отказа для dp[i][n-1] конфигураций, поэтому мы должны записать столько же новых раз до отказа после введения нового компонента.

Почему большие простые числа не влияют на количество состояний?

Каждое из них встречается либо 0, либо 1 раз. Не следует ли умножать количество состояний на 2 для каждого из этих простых чисел (что снова приводит к недопустимому пространству состояний)?

Вы правы, конечно. Однако в наброске решения указано, что числа с большими простыми числами обрабатываются другим (неуказанным) способом.

Что произойдет, если мы их включим? Количество состояний, которые нам нужно было бы представить, превратилось бы в непрактичное число. Поэтому автор объясняет такие числа по-разному. Обратите внимание, что если число, меньшее или равное 500, включает простое число больше 19, другие множители умножаются на 21 или меньше. Это делает такие числа пригодными для грубой силы, таблицы не нужны.

person Kaganar    schedule 31.10.2014
comment
Я думаю, что это точно отвечает на конкретные вопросы. Я обнаружил, что часть о рекуррентном отношении несколько трудна для понимания (я не уверен, что добавленный вами контекст делает ее проще, чем если бы вы просто решили абстрактную проблему или нет), но это кажется правильным. - person Vincent van der Weele; 06.11.2014
comment
По общему признанию, я очень старался быть последовательным в формулировке автора наброска — похоже, у автора в голове была определенная схема, из которой он использовал терминологию, хотя она и не соответствовала поставленной задаче. Так что я думаю, что вы, вероятно, правы - я получил худшее из обоих миров - несколько неверная терминология и эзотерический способ решения проблемы. Спасибо, что пролили свет на это - это поможет мне улучшить ответы в будущем. - person Kaganar; 06.11.2014

Первая часть редакционной статьи кажется полезной, но вторая часть довольно расплывчата (и, возможно, бесполезна; я скорее закончу этот ответ, чем разберусь в нем).

Предположим на данный момент, что входные данные состоят из попарно различных простых чисел, например, 2, 3, 5 и 7. Тогда ответ (для суммирования всех множеств, где НОК нулевых целых чисел равен 1)

(1 + 2) (1 + 3) (1 + 5) (1 + 7),

потому что НОК подмножества в точности равен произведению здесь, так что просто умножьте его.

Ослабим ограничение на то, что простые числа попарно различны. Если у нас есть ввод, например 2, 2, 3, 3, 3 и 5, то умножение выглядит как

(1 + (2^2 - 1) 2) (1 + (2^3 - 1) 3) (1 + (2^1 - 1) 5),

потому что 2 появляется с кратностью 2, а 3 появляется с кратностью 3, а 5 появляется с кратностью 1. Что касается, например, только набора троек, существует 2^3 - 1 способов выбрать подмножество, включающее 3, и 1 способа выберите пустой набор.

Назовите простое маленьким, если оно равно 19 или меньше, и большим в противном случае. Обратите внимание, что целые числа 500 или меньше делятся не более чем на одно большое простое число (с кратностью). Маленькие простые числа более проблематичны. Что мы собираемся сделать, так это вычислить для каждой возможной небольшой части простой факторизации НОК (т. е. одного из примерно 70 000 состояний) сумму НОК для задачи, полученной путем отбрасывания целых чисел, которые не могут делиться такой LCM и оставляя только большой простой множитель (или 1) для других целых чисел.

Например, если на входе 2, 30, 41, 46 и 51, а состояние равно 2, то мы сохраняем 2 как 1, отбрасываем 30 (= 2 * 3 * 5; 3 и 5 маленькие), сохраняем 41 как 41 (41 большое), сохранить 46 как 23 (= 2 * 23; 23 большое) и отбросить 51 (= 3 * 17; 3 и 17 маленькие). Теперь мы вычисляем сумму LCM, используя ранее описанную технику. Используйте включение-исключение, чтобы избавиться от подмножеств, LCM которых малая часть которых правильно делит состояние вместо того, чтобы быть точно равным. Может быть, я буду работать полный пример позже.

person David Eisenstat    schedule 30.10.2014
comment
к вашему сведению: кажется, что ОП спрашивает конкретно о второй части... Если вы чего-то не понимаете, это не означает автоматически, что это бесполезно. - person artur grzesiak; 31.10.2014
comment
@arturgrzesiak Менее вежливо, я думаю, что это неправильно, но это настолько расплывчато, что, возможно, даже не так. - person David Eisenstat; 31.10.2014
comment
Было бы полезно, если бы вы добавили более конкретно, как использовать включение-исключение в этой ситуации, но этот ответ дал много полезных советов. - person Vincent van der Weele; 06.11.2014

What is meant by these states?

Я думаю, что здесь состояния относятся к тому, находится ли число в наборе B = {b0, b1,..., bk-1} LCM набора A.

Does dp stand for dynamic programming and if so, what recurrence relation is being solved?

Я полагаю, что dp в эскизе решения означает динамическое программирование.

How is dp[i] computed from dp[i-1]?

Вполне возможно, что мы можем определить состояние следующей группы LCM из предыдущих состояний. Итак, нам нужен только массив из 2 и переключение туда и обратно.

Why do the big primes not contribute to the number of states? Each of them occurs either 0 or 1 times. Should the number of states not be multiplied by 2 for each of these primes (leading to a non-feasible state space again)?

Мы можем использовать простую факторизацию и показатели степени только для представления числа.

Вот один пример.

6 = (2^1)(3^1)(5^0) -> состояние "1 1 0" для представления 6 18 = (2^1)(3^2)(5^0) -> состояние "1 2 0" для представления 18

Вот как мы можем получить LMC 6 и 18, используя Prime Factorization

НОК (6,18) = (2 ^ (макс. (1,1)) (3 ^ (макс. (1,2)) (5 ​​^ макс. (0,0)) = (2 ^ 1) (3 ^ 2) (5^0) = 18

2^9 > 500, 3^6 > 500, 5^4 > 500, 7^4>500, 11^3 > 500, 13^3 > 500, 17^3 > 500, 19^3 > 500

мы можем использовать только подсчет показателей простого числа 2, 3, 5, 7, 11, 13, 17, 19 для представления LCM в наборе B = {b0, b1, ..., bk-1} для данного установить A = {a0, a1, ..., aN-1} (1 ≤ N ≤ 100), где 2 ≤ ai ≤ 500.

9 * 6 * 4 * 4 * 3 * 3 * 3 * 3 ‹= 70000, поэтому нам нужно только два dp[9][6][4][4][3][3][3][3] для отслеживания всех состояний LCM. Итак, dp[70000][2] достаточно.

Я составил небольшую программу на C++, чтобы проиллюстрировать, как мы можем получить сумму LCM заданного множества A = {a0, a1, ..., aN-1} (1 ≤ N ≤ 100), где 2 ≤ ai ≤ 500. В эскизе решения нам нужно перебрать 70000 максимально возможных LCM.

int gcd(int a, int b) {
    int remainder = 0;
    do {
        remainder = a % b;
        a = b;
        b = remainder;
    } while (b != 0);
    return a;
}

int lcm(int a, int b) {
    if (a == 0 || b == 0) {
        return 0;
    }
    return (a * b) / gcd(a, b);
}


int sum_of_lcm(int A[], int N) {

    // get the max LCM from the array
    int max = A[0];
    for (int i = 1; i < N; i++) {
        max = lcm(max, A[i]);
    }
    max++;

    //
    int dp[max][2];
    memset(dp, 0, sizeof(dp));
    int pri = 0;
    int cur = 1;

    // loop through n x 70000
    for (int i = 0; i < N; i++) {
        for (int v = 1; v < max; v++) {
            int x = A[i];
            if (dp[v][pri] > 0) {
                x = lcm(A[i], v);
                dp[v][cur] = (dp[v][cur] == 0) ? dp[v][pri] : dp[v][cur];
                if ( x % A[i] != 0 ) {
                    dp[x][cur] += dp[v][pri] + dp[A[i]][pri];
                } else {
                    dp[x][cur] += ( x==v ) ? ( dp[v][pri] + dp[v][pri] ) : ( dp[v][pri] ) ;
                }
            }
        }
        dp[A[i]][cur]++;
        pri = cur;
        cur = (pri + 1) % 2;
    }

    for (int i = 0; i < N; i++) {
        dp[A[i]][pri] -= 1;
    }
    long total = 0;
    for (int j = 0; j < max; j++) {
        if (dp[j][pri] > 0) {
            total += dp[j][pri] * j;
        }
    }
    cout << "total:" << total << endl;

    return total;
}



int test() {
    int a[] = {2, 6, 7 };
    int n = sizeof(a)/sizeof(a[0]);
    int total = sum_of_lcm(a, n);
    return 0;
}

Output
total:104
person stones333    schedule 02.11.2014
comment
Попробуйте запустить код примера с вводом [2^8, 3^5, ..., 491, 499]. Размер массива A становится немного выше 70000, тогда... - person Vincent van der Weele; 02.11.2014
comment
Это иллюстрация DP для расчета суммы LCM, идея. - person stones333; 03.11.2014

Состояний на единицу больше, чем степеней простых чисел. У вас есть числа до 2 ^ 8, поэтому степень 2 находится в [0..8], что составляет 9 состояний. Аналогично для других штатов.

«dp» вполне может означать динамическое программирование, я не уверен.

Рекуррентное соотношение является сердцевиной проблемы, поэтому вы узнаете больше, решая ее самостоятельно. Начните с небольших простых примеров.

Для больших простых чисел попробуйте решить упрощенную задачу, не используя их (или их эквиваленты), а затем добавьте их обратно, чтобы увидеть их влияние на конечный результат.

person rossum    schedule 21.10.2014
comment
Я чувствую, что этот ответ объясняет все, кроме сложной части. Каков аспект динамического программирования предлагаемого решения? - person Teepeemm; 22.10.2014
comment
@Teepeemm: Точно. Как я уже сказал, вы узнаете больше, решив ее самостоятельно. - person rossum; 22.10.2014
comment
Но единственное, что добавил ваш ответ, - это четко указать, что 9 * 6 * 4 * 4 * 3 * 3 * 3 * 3 исходит из полномочий простых чисел. Кроме этого (очевидного?) факта, этот ответ ничего не добавляет. - person Teepeemm; 22.10.2014
comment
@Teepeemm: прочитайте еще раз, начните с небольших простых примеров. - person rossum; 22.10.2014
comment
Я полностью согласен с вами в том, что лучший способ научиться — это выяснить для себя. Но что заставляет вас думать, что ОП не пробовал какие-то маленькие простые примеры? В настоящее время это не ответ на вопрос, а просто комментарий. - person Vincent van der Weele; 25.10.2014