import time
import random
def distribute(arr, x):
total = sum(arr) + x
I = sorted(range(len(arr)), key=arr.__getitem__)
while I:
minimum, additional = divmod(total, len(I))
if arr[I[-1]] <= minimum:
break
total -= arr[I.pop()]
for i in sorted(I):
arr[i] = minimum
if additional > 0:
arr[i] += 1
additional -= 1
def f(A, x):
smallest = min(A)
lo = smallest
hi = smallest + x
while lo < hi:
mid = lo + (hi - lo) // 2
can_reach = True
temp = x
for a in A:
if a <= mid:
diff = mid - a
if diff > temp:
can_reach = False
break
else:
temp -= diff
if can_reach:
lo = mid + 1
else:
hi = mid
target = lo - 1
for i, a in enumerate(A):
if a < target:
x -= target - a
A[i] = target
if x:
for i, a in enumerate(A):
if a == target:
A[i] += 1
x -= 1
if x == 0:
break
return A
n = 1000000
m = 20
x = int(random.random() * m)
A = [random.randint(0, m) for _ in range(n)]
A1 = A.copy()
t0 = time.time()
distribute(A, x)
print(time.time() - t0)
t0 = time.time()
f(A1, x)
print(time.time() - t0)
print(sorted(A) == sorted(A1))
m = 100000000
x = int(random.random() * m)
A = [random.randint(0, m) for _ in range(n)]
A1 = A.copy()
t0 = time.time()
distribute(A, x)
print(time.time() - t0)
t0 = time.time()
f(A1, x)
print(time.time() - t0)
print(sorted(A) == sorted(A1))
aW1wb3J0IHRpbWUKaW1wb3J0IHJhbmRvbQoKCmRlZiBkaXN0cmlidXRlKGFyciwgeCk6CiAgICB0b3RhbCA9IHN1bShhcnIpICsgeAogICAgSSA9IHNvcnRlZChyYW5nZShsZW4oYXJyKSksIGtleT1hcnIuX19nZXRpdGVtX18pCiAgICB3aGlsZSBJOgogICAgICAgIG1pbmltdW0sIGFkZGl0aW9uYWwgPSBkaXZtb2QodG90YWwsIGxlbihJKSkKICAgICAgICBpZiBhcnJbSVstMV1dIDw9IG1pbmltdW06CiAgICAgICAgICAgIGJyZWFrCiAgICAgICAgdG90YWwgLT0gYXJyW0kucG9wKCldCiAgICBmb3IgaSBpbiBzb3J0ZWQoSSk6CiAgICAgICAgYXJyW2ldID0gbWluaW11bQogICAgICAgIGlmIGFkZGl0aW9uYWwgPiAwOgogICAgICAgICAgICBhcnJbaV0gKz0gMQogICAgICAgICAgICBhZGRpdGlvbmFsIC09IDEKCmRlZiBmKEEsIHgpOgogIHNtYWxsZXN0ID0gbWluKEEpCgogIGxvID0gc21hbGxlc3QKICBoaSA9IHNtYWxsZXN0ICsgeAoKICB3aGlsZSBsbyA8IGhpOgogICAgbWlkID0gbG8gKyAoaGkgLSBsbykgLy8gMgoKICAgIGNhbl9yZWFjaCA9IFRydWUKICAgIHRlbXAgPSB4CgogICAgZm9yIGEgaW4gQToKICAgICAgaWYgYSA8PSBtaWQ6CiAgICAgICAgZGlmZiA9IG1pZCAtIGEKICAgICAgICBpZiBkaWZmID4gdGVtcDoKICAgICAgICAgIGNhbl9yZWFjaCA9IEZhbHNlCiAgICAgICAgICBicmVhawogICAgICAgIGVsc2U6CiAgICAgICAgICB0ZW1wIC09IGRpZmYKCiAgICBpZiBjYW5fcmVhY2g6CiAgICAgIGxvID0gbWlkICsgMQogICAgZWxzZToKICAgICAgaGkgPSBtaWQKCiAgdGFyZ2V0ID0gbG8gLSAxCgogIGZvciBpLCBhIGluIGVudW1lcmF0ZShBKToKICAgIGlmIGEgPCB0YXJnZXQ6CiAgICAgIHggLT0gdGFyZ2V0IC0gYQogICAgICBBW2ldID0gdGFyZ2V0CgogIGlmIHg6CiAgICBmb3IgaSwgYSBpbiBlbnVtZXJhdGUoQSk6CiAgICAgIGlmIGEgPT0gdGFyZ2V0OgogICAgICAgIEFbaV0gKz0gMQogICAgICAgIHggLT0gMQogICAgICAgIGlmIHggPT0gMDoKICAgICAgICAgIGJyZWFrCiAgCiAgcmV0dXJuIEEKCgpuID0gMTAwMDAwMAoKCm0gPSAyMAp4ID0gaW50KHJhbmRvbS5yYW5kb20oKSAqIG0pCkEgPSBbcmFuZG9tLnJhbmRpbnQoMCwgbSkgZm9yIF8gaW4gcmFuZ2UobildCkExID0gQS5jb3B5KCkKCnQwID0gdGltZS50aW1lKCkKZGlzdHJpYnV0ZShBLCB4KQpwcmludCh0aW1lLnRpbWUoKSAtIHQwKQoKCnQwID0gdGltZS50aW1lKCkKZihBMSwgeCkKcHJpbnQodGltZS50aW1lKCkgLSB0MCkKCnByaW50KHNvcnRlZChBKSA9PSBzb3J0ZWQoQTEpKQoKCm0gPSAxMDAwMDAwMDAKeCA9IGludChyYW5kb20ucmFuZG9tKCkgKiBtKQpBID0gW3JhbmRvbS5yYW5kaW50KDAsIG0pIGZvciBfIGluIHJhbmdlKG4pXQpBMSA9IEEuY29weSgpCgp0MCA9IHRpbWUudGltZSgpCmRpc3RyaWJ1dGUoQSwgeCkKcHJpbnQodGltZS50aW1lKCkgLSB0MCkKCgp0MCA9IHRpbWUudGltZSgpCmYoQTEsIHgpCnByaW50KHRpbWUudGltZSgpIC0gdDApCgpwcmludChzb3J0ZWQoQSkgPT0gc29ydGVkKEExKSk=