본문 바로가기

PS/AtCoder

[AtCoder abc136] E-Max GCD[python]

 

 

E - Max GCD

AtCoder is a programming contest site for anyone from beginners to experts. We hold weekly programming contests online.

atcoder.jp

Time Limit: 2 sec / Memory Limit: 1024 MB

Score : 500 points

Problem Statement

We have a sequence of N integers: A_1, A_2, \cdots, A_N.

You can perform the following operation between 0 and K times (inclusive):

  • Choose two integers i and j such that i \neq j, each between 1 and N (inclusive). Add 1 to A_i and -1 to A_j, possibly producing a negative element.

Compute the maximum possible positive integer that divides every element of A after the operations. Here a positive integer xx divides an integer y if and only if there exists an integer z such that y = xz.

Constraints

All values in input are integers.

======================================================================

주어진 수열 A의 숫자들을 대상으로 Operation(한 수에는 +1, 다른 한 수에는 -1)이 아무리 이루어지더라도, 

수열 A의 총 합$S$는 변하지 않는다는 성질을 이용합니다.

 

합$S$에 대해, 문제에서 구하고자 하는 GCD는 $S$의 약수중에 있음을 알 수 있습니다.

(Operation 이후 수열 A의 모든 수가 어떤 수 $X$에 의해 나누어 떨어진다면, 이 수는 $S$의 약수여야 합니다.)

$if$  $Sum($$A_i$  $mod$ $X) = 0,$ $S$ $mod$ $X= 0$

 

모든 수가 X에 의해 나누어 떨어지도록 값들을 변경하는 과정에서, 결과적으로 어떤 수는 $A_i$ $mod$ $X$값을 빼주어야 할 것이고, 어떤 수는 $N - $$A_i$ $mod$ $X$값을 더해주어야 할 것입니다.

모든 $A_i$을 $mod$ $X$한 결과수열을 PS, X - $(A_i$ $mod$ $X)$한 결과수열을 SS라고 할 때,

$X-(A_i$ $mod$ $X)-A_i$ $mod$ $X = X$이므로 어느 한쪽의 총 합에서 특정 요소값(V)을 빼고

반대쪽에는 X-V를 더해준다면, 둘의 차이는 D씩 감소하며,  Sum(SS),Sum(PS) 모두 X의 배수이므로 둘의 값은 특정 시점에서 같아집니다.

 

이 때, 모든 값이 X에 의해 나누어 떨어질 수 있도록 하는 Operation의 최소 수행 횟수 M은 Sum(SS),Sum(PS)값이 만나는 지점의 값과 같으며, ( 배열 내의 수들에 대해 수열 SS 내에 있는 수들은 총 M만큼 값을 빼주고, 수열 PS 내에 있는 수들은 총 M만큼 값을 더해줍니다.) M값을 구하기 위해선, Sum(SS),Sum(PS)가 가능한 작은 수에서 만나도록 해야합니다.

 

Sum(SS)에서 요소를 빼주고, Sum(PS) = 0으로 시작해 요소를 채워나간다고 할 때,

Sum(SS)에서 가능한 한 큰 수를 빼주면(PS에 가능한 한 작은 수를 더해주면) M값을 최소화할 수 있습니다.

 

그렇게 두 값이 같아졌을 때, M값과 K값을 비교하여, M값이 K보다 작거나 같은 경우 주어진 조건을 만족함을 알 수 있습니다.

 

n,k = map(int,input().split())
nums = list(map(int,input().split()))
total = sum(nums)
for i in range(total,0,-1):
    if total % i: continue

    prefixSum = 0
    suffix = []
    for v in nums:
        if v % i:
            prefixSum += i - (v % i)  #숫자 i로 나눈 나머지
            suffix.append(v % i)

    if not prefixSum:
        print(i)
        exit(0)

    suffix.sort()    #큰거부터 차례대로 빼기
    suffixSum = 0
    for v in suffix:
        prefixSum -= (i - v)    #v%i 뺴줌
        suffixSum += v

        #print(abs(prefixSum - suffixSum))
        if prefixSum == suffixSum and prefixSum <= k:
            print(i)
            exit(0)


728x90