Автор проблеми: | 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). Якщо ми встановимо
то ми наразі маємо
і також
Назвемо цю поточну обмежену суму \text{tot} = n \cdot B.
Ми хочемо, щоб обмежена сума стала точною . Оскільки наразі кожне A_i \le B \le b, зменшення A_i на також зменшить \min(A_i,b) на . Тому ми проходимо від i=1 до і поки \text{tot} > c намагаємось зменшити A_i. Для фіксованої позиції ми не можемо зменшити більше, ніж те, що ще є зайвим, і не можемо опуститися нижче , тому беремо
і виконуємо
Після одного проходу рівність
виконується, оскільки кожна одиниця, яку ми відняли від деякого 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, тоді після зменшення ми маємо правильну обмежену суму, але можливо
Щоб збільшити реальну суму, не змінюючи обмежену суму, ми торкаємось лише позицій з A_i = b. Якщо ми збільшуємо таке A_i до b + \delta з \delta \le n-b, тоді
але реальна сума збільшується на . Тому ми знову скануємо і щоразу, коли A_i = b і поточна сума все ще , ми додаємо
до A_i. Оскільки проблема обіцяє, що розв'язок існує, ми знайдемо достатньо таких позицій, щоб досягти точної суми . Ми ніколи не порушуємо A_i \le n, оскільки ми лише підвищуємо з до максимуму .
Отже, конструкція є такою:
встановіть все на B = \min(b,n);
зменшуйте з початку, щоб зробити обмежену суму рівною ;
якщо 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)