Мінімальна сума конструкції#12262

Мінімальна сума конструкції (Розбір)

Автор проблеми:

Hasan Saleh (MathModel)

Підготовлено:

Hasan Saleh (MathModel)

Редаговано:

Hasan Saleh (MathModel)

Розв'язок

Вам потрібно побудувати масив довжини так, щоб 1 \le A_i \le n, \sum_{i=1}^n A_i = a і \sum_{i=1}^n \min(A_i,b) = c. Умова з мінімумом є обмежувальною, тому спочатку ми зробимо цю суму правильною, а потім виправимо реальну суму.

Зверніть увагу, що нам ніколи не потрібно починати з значення, більшого за , оскільки значення все одно обмежені , і будь-яке значення дає той же внесок до обмеженої суми. Нехай B = \min(b,n). Якщо ми встановимо

A_i = B \quad \text{для всіх } i=1,\dots,n,

то ми наразі маємо

\sum_{i=1}^n \min(A_i,b) = \sum_{i=1}^n B = n \cdot B,

і також

\sum_{i=1}^n A_i = n \cdot B.

Назвемо цю поточну обмежену суму \text{tot} = n \cdot B.

Ми хочемо, щоб обмежена сума стала точною . Оскільки наразі кожне A_i \le B \le b, зменшення A_i на також зменшить \min(A_i,b) на . Тому ми проходимо від i=1 до і поки \text{tot} > c намагаємось зменшити A_i. Для фіксованої позиції ми не можемо зменшити більше, ніж те, що ще є зайвим, і не можемо опуститися нижче , тому беремо

v = \min\{\, \text{tot} - c,\; A_i - 1,\; B - 1 \,\}

і виконуємо

A_i \gets A_i - v,\quad \text{tot} \gets \text{tot} - v.

Після одного проходу рівність

\sum_{i=1}^n \min(A_i,b) = c

виконується, оскільки кожна одиниця, яку ми відняли від деякого A_i \le b, зменшила обмежену суму точно на .

Тепер ми перевіряємо реальну суму \sum A_i. Якщо b \ge n, тоді B = n і \min(A_i,b) = A_i для всіх , тому як тільки обмежена сума дорівнює , ми вже маємо \sum A_i = c, і оскільки умова гарантує, що розв'язок існує, ми повинні мати a=c і ми закінчили.

Якщо b \le n, тоді після зменшення ми маємо правильну обмежену суму, але можливо

\sum_{i=1}^n A_i < a.

Щоб збільшити реальну суму, не змінюючи обмежену суму, ми торкаємось лише позицій з A_i = b. Якщо ми збільшуємо таке A_i до b + \delta з \delta \le n-b, тоді

\min(A_i,b) = b \quad \text{(незмінно)},

але реальна сума збільшується на . Тому ми знову скануємо і щоразу, коли A_i = b і поточна сума все ще , ми додаємо

\delta = \min(a - \text{sum},\; n - b)

до A_i. Оскільки проблема обіцяє, що розв'язок існує, ми знайдемо достатньо таких позицій, щоб досягти точної суми . Ми ніколи не порушуємо A_i \le n, оскільки ми лише підвищуємо з до максимуму .

Отже, конструкція є такою:

  1. встановіть все на B = \min(b,n);

  2. зменшуйте з початку, щоб зробити обмежену суму рівною ;

  3. якщо b \le n, підвищуйте лише позиції, які наразі дорівнюють , щоб зробити реальну суму рівною .

Складність становить \mathcal{O}(\sum n).

for _ in range(int(input())):
    n,a,b,c=map(int,input().split())
    base=min(b,n)
    res=[base]*n
    tot=n*base
    i=0
    while i<n and tot>c:
        v=min(tot-c,res[i]-1,base-1)
        if v>0:
            res[i]-=v
            tot-=v
        i+=1
    if b<=n:
        i=0
        while i<n and tot<a:
            if res[i]==b:
                v=min(a-tot,n-b)
                if v>0:
                    res[i]+=v
                    tot+=v
            i+=1
    print(*res)