Авiашляхи Потоколяндiї#314

Автор: Єгор Дубовік

Розробник: Ігор Баренблат

Визначимо a \subset b — вираз, що означає, що b=a ( є «підмаскою» ). Тут  — побітове І.

Розв'язуватимемо задачу покроково.

  1. Визначимо D_i — -бітова маска, де -ий біт рівний , якщо місто з номером належить списку з номером , та в протилежному випадку.

    Як порахувати ? Це домашнє завдання :)

  2. Визначимо cntD_i — кількість таких , що D_j = i.

    Як порахувати ? Це домашнє завдання :)

  3. Визначимо intersect_{mask} — кількість авіашляхів, що можуть утворитися за використання будь-якого зі списків, що відповідають одиничним бітам -бітової маски .

    Як порахувати ? intersect_{mask}={sum_{mask \subset a} cntD_a}\choose{2} (Для того щоб швидко порахувати значення, використовуйте ідею super magic algo(описано нижче)).

  4. Визначимо union_{mask} — кількість авіашляхів, що будуть утворені за використання списків, що відповідають одиничним бітам -бітової маски (помітимо, що це значення не залежить від порядку використання списків).

    Як порахувати ? Посилаючись на формулу включень-виключень, отримуємо: union_{mask}=sum_{a\subset mask} ((-1)^{bits(a)+1}\cdot intersect_a) (Для того щоб швидко порахувати значення, використовуйте super magic algo(описано нижче)). Тут  — кількість одиничних бітів маски .

  5. Розв'язуватимемо задачу методом динамічного програмування. Визначимо dp_{mask} — максимальна кількість грошових одиниць, які можна заробити, використавши списки, що відповідають одиничним бітам -бітової маски у довільному порядку.

    Як порахувати ? dp_0=0. dp_{mask}=\max (dp_{mask} _{xor} _{2^i} + f(union_{mask}-union_{mask} _{xor} _{2^i}) \cdot r_i), де  — номери одиничних бітів -бітової маски . Тут  — побітове виключне АБО.

    Відповіддю до задачі є dp_{2^{m}-1}.

/// super magic algo

Нехай задається масив розміру 2^m. Необхідно знайти значення масиву , де b_i=sum_{j \subset i} a_j.

Здійснимо ітерацій, де після ітерації з номером значенням буде \sum_{}a[y], таких що y = y, та починаючи з біта з номером біти чисел та збігаються (біти нумеруються з 0).

Очевидно, що перед першою ітерацією b[x]=a[x]. На ітерації з номером перерахуємо .

Якщо в числі x біт з номером рівний , то b_{new}[x]=b[x].

Якщо в числі x біт з номером рівний , то b_{new}[x]=b[x]+b[x 2^i].

Отже, легко реалізувати цей алгоритм так:

for (int i=0;i<(1<<m);i++){
    b[i]=a[i];
}
for (int i=0;i<m;i++){
    for (int mask=0;mask<(1<<m);mask++){
        if (mask&(1<<i)){
            b[mask]+=b[mask^(1<<i)];
        }
    }
}

/// end of super magic algo

Складність O(n\cdot m+m\cdot 2^m) часу та O(n+2^m) пам'яті.