Количество положительных решений для a1 x1 + a2 x2 + ...... + a xn = k (k <= 10 ^ 18) - PullRequest
3 голосов
/ 03 ноября 2011

Вопрос в том, сколько решений a1 x1 + a2 x2 + .... + a xn = k с ограничениями: 1) ai> 0 и ai <= 15 2) n> 0 и n <= 15 3) xi > = 0 Мне удалось сформулировать решение для динамического программирования, но оно слишком долго для n> 10 ^ 10. Пожалуйста, направьте меня, чтобы получить более эффективный способ. Код

int dp[]=new int[16];
        dp[0]=1;
        BigInteger seen=new BigInteger("0");
        while(true)
        {
            for(int i=0;i<arr[0];i++)
            {
                if(dp[0]==0)
                    break;
                dp[arr[i+1]]=(dp[arr[i+1]]+dp[0])%1000000007;
            }
            for(int i=1;i<15;i++)
                dp[i-1]=dp[i];
            seen=seen.add(new BigInteger("1"));
            if(seen.compareTo(n)==0)
            break;
        }
        System.out.println(dp[0]);

arr - массив, содержащий коэффициенты, и ответ должен быть mod 1000000007, поскольку число способов не вписывается в int.

1 Ответ

1 голос
/ 05 ноября 2011

Обновление для реальной проблемы:

Актуальная проблема намного проще.Тем не менее, трудно быть полезным без полной порчи.

Разбирая это до самого необходимого, проблема в

Учитывая k различных положительных целых чисел L1 , ..., Lk и неотрицательное целое число n , сколько различных конечных последовательностей ( a1 , ..., ar ) существуют ли такие, что 1. для всех i (1 <= <em>i <= <em>r ), ai является одним из Lj и 2. a1 + ... + ar = n .(Другими словами, количество композиций из n с использованием только данных Lj .)

Для удобства вытакже сказал, что все Lj <= 15 (и, следовательно, <em>k <= 15) и <em>n <= 10 ^ 18.И чтобы все вычисления можно было выполнить с использованием 64-разрядных целых чисел (число последовательностей растет экспоненциально с <em>n , у вас не было бы достаточно памяти для хранения точного числа для больших n), вам нужно только вычислить остаток от числа последовательностей по модулю 1000000007.

Чтобы решить такую ​​проблему, начните с рассмотрения простейших случаев.Самые простые случаи, когда дается только один L , тогда, очевидно, существует одна допустимая последовательность, если n кратна L , и нет допустимой последовательности, если n мод L ! = 0. Это пока не помогает.Итак, рассмотрим следующие простейшие случаи: два значения L .Предположим, что это 1 и 2.

  1. 0 имеет одну композицию, пустая последовательность: N (0) = 1
  2. 1 имеет одну композицию, (1): N (1)= 1
  3. 2 имеет две композиции (1,1);(2): N (2) = 2
  4. 3 имеет три состава: (1,1,1); (1,2); (2,1): N (3) = 3
  5. 4 состоит из пяти композиций: (1,1,1,1); (1,1,2); (1,2,1); (2,1,1); (2,2): N (4) = 5
  6. 5 имеет восемь композиций, (1,1,1,1,1); (1,1,1,2); (1,1,2,1); (1,2,1,1); (2,1,1,1); (1,2,2); (2,1,2); (2,2,1): N (5) = 8

Вы можете увидеть это сейчас или вам понадобится еще несколько терминов, но вы заметите, что вы получаете последовательность Фибоначчи (смещенную на единицу), N ( n ) = F ( n + 1), следовательно, последовательность N ( n ) удовлетворяет рекуррентному отношению N ( n ) = N ( n -1) + N ( n -2) (для n > = 2; мы еще не доказали, что пока это гипотеза, основанная на определении шаблона),Теперь мы можем увидеть это, не вычисляя много значений?Конечно, есть два типа допустимых последовательностей, заканчивающиеся на 1 и заканчивающиеся на 2. Поскольку такое разбиение допустимых последовательностей ограничивает только последний элемент, число объявлений.сл.сумма до n и заканчивающаяся 1 равна N ( n -1) и номеру объявления.сл.сумма до n и заканчивающаяся на 2 равен N ( n -2).

Это рассуждение немедленно обобщается, учитывая L1 <<em>L2 <... <<em> Lk , для всех n > = Lk , у нас есть

N ( n ) = N ( n-L1 ) + N ( n-L2 ) + ... + N ( n-Lk )

с очевидной интерпретацией, если нас интересует только N ( n )% m .

Умм, эта линейная повторяемостьвсе еще оставляет вычисление N ( n ) как задачу O ( n )?
Да, но исследование нескольких из упомянутых ключевых слов быстро приводит к алгоритму, требующему только O (log n ) steps;)

Алгоритм для неверно истолкованной проблемы, более не актуален, но все еще может быть интересен:

Вопрос выглядит немного странно, поэтому я не буду приводить полный алгоритм (по крайней мере, не раньше, чем немного погуглю, чтобы проверить, является ли это конкурсным вопросом). Я надеюсь, что никакое ограничение не было опущено в описании, например, что перестановки таких представлений должны вносить только одно в подсчет, что значительно усложнит вопрос. Поэтому я считаю 1*3 + 2*4 = 11 и 2*4 + 1*3 = 11 двумя различными решениями.

Сначала несколько обозначений. Для m-кортежей чисел пусть < | > обозначает каноническое билинейное спаривание, т.е.
<a|x> = a_1*x_1 + ... + a_m*x_m. Для положительного целого числа B пусть A_B = {1, 2, ..., B} будет набором натуральных чисел, не превышающих B. Пусть N обозначает набор натуральных чисел, то есть неотрицательных целых чисел.
Для 0 <= m, k и B > 0 пусть C(B,m,k) = card { (a,x) \in A_B^m × N^m : <a|x> = k }.

Тогда ваша проблема - найти \sum_{m = 1}^15 C(15,m,k) (по модулю 1000000007).

Для полноты отметим, что C(B,0,k) = if k == 0 then 1 else 0, что может быть полезно в теоретических соображениях. Для случая положительного числа слагаемых легко найти формулу рекурсии

C(B,m+1,k) = \sum_{j = 0}^k C(B,1,j) * C(B,m,k-j)

По индукции C(B,m,_) - это свертка из m факторов C(B,1,_). Вычисление свертки двух известных функций до k равно O(k^2), поэтому, если известно C(B,1,_), это дает алгоритм O(n*k^2) для вычисления C(B,m,k), 1 <= m <= n. Ладно для малых k, но наша галактика не доживет до того, что вы вычислите C(15,15,10^18) таким образом Итак, мы можем сделать лучше? Что ж, если вы знакомы с преобразованием Лапласа, вы будете знать, что аналогичное преобразование преобразует продукт свертки в точечный продукт, который гораздо проще вычислить. Однако, хотя преобразование в этом случае легко вычислить, обратное - нет. Любая другая идея? Почему, да, давайте подробнее рассмотрим C(B,1,_).

C(B,1,k) = card { a \in A_B : (k/a) is an integer }

Другими словами, C(B,1,k) - это число делителей k, не превышающее B. Обозначим это через d_B(k). Сразу видно, что 1 <= d_B(k) <= B. Для B = 2, очевидно d_2(k) = 1 if k is odd, 2 if k is even. d_3(k) = 3 тогда и только тогда, когда k делится на 2 и на 3, следовательно, если k кратно 6, d_3(k) = 2 тогда и только тогда, когда одно из 2, 3 делит k, но не другое, то есть, если k % 6 \in {2,3,4} и, наконец, d_3(k) = 1, если ни 2, ни 3 не делит k, то есть, если gcd(k,6) = 1, тогда k % 6 \in {1,5}. Итак, мы видели, что d_2 является периодическим с периодом 2, d_3 является периодическим с периодом 6. Как правило, подобные рассуждения показывают, что d_B является периодическим для всех B, а минимальный положительный период делит B!.

При любом положительном периоде P, равном C(B,1,_) = d_B, мы можем разделить сумму в свертке (k = q * P + r, 0 <= r <P): </p>

C(B,m+1, q*P+r) = \sum_{c = 0}^{q-1} (\sum_{j = 0}^{P-1} d_B(j)*C(B,m,(q-c)*P + (r-j)))
                + \sum_{j = 0}^r d_B(j)*C(B,m,r-j)

Функции C(B,m,_) больше не являются периодическими для m >= 2, но есть простые формулы для получения C(B,m,q*P+r) из C(B,m,r). Таким образом, с C(B,1,_) = d_B и C(B,m,_), известными до P, вычисление C(B,m+1,_) до P является задачей O(P^2), получение данных, необходимых для вычисления C(B,m+1,k) для произвольно большого k, требует m таких сверток, следовательно, это O(m*P^2).

Тогда нахождение C(B,m,k) для 1 <= m <= n и произвольно большого k будет O(n^2*P^2) во времени и O(n^2*P) в пространстве.
Для B = 15 у нас есть 15! = 1.307674368 * 10 ^ 12, поэтому использовать его для P невозможно. К счастью, наименьший положительный период d_15 на намного меньше, так что вы получите что-то работоспособное. По приблизительной оценке, я все же ожидал бы, что вычисление C(15,15,k) займет время, более точно измеренное в часах, чем секундах, но это улучшение по сравнению с O(k), которое заняло бы годы (для k в области 10 ^ 18).

used Используемая здесь свертка (f \ast g)(k) = \sum_{j = 0}^k f(j)*g(k-j).
² Предполагая, что все арифметические операции O (1); если, как и в ОП, требуется только вычет по модулю некоторого M> 0, это верно, если все промежуточные вычисления выполнены по модулю M.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...