문제
트럭을 타고 이동하던 상근이는 경찰의 검문을 받게 되었다. 경찰은 상근이가 운반하던 화물을 하나하나 모두 확인할 것이기 때문에, 검문하는데 엄청나게 오랜 시간이 걸린다.
상근이는 시간을 때우기 위해서 수학 게임을 하기로 했다.
먼저 근처에 보이는 숫자 N개를 종이에 적는다. 그 다음, 종이에 적은 수를 M으로 나누었을 때, 나머지가 모두 같게 되는 M을 모두 찾으려고 한다. M은 1보다 커야 한다.
N개의 수가 주어졌을 때, 가능한 M을 모두 찾는 프로그램을 작성하시오.
입력
첫째 줄에 종이에 적은 수의 개수 N이 주어진다. (2 ≤ N ≤ 100)
다음 줄부터 N개 줄에는 종이에 적은 수가 하나씩 주어진다. 이 수는 모두 1보다 크거나 같고, 1,000,000,000보다 작거나 같은 자연수이다. 같은 수가 두 번 이상 주어지지 않는다.
항상 M이 하나 이상 존재하는 경우만 입력으로 주어진다.
출력
첫째 줄에 가능한 M을 공백으로 구분하여 모두 출력한다. 이때, M은 증가하는 순서이어야 한다.
예제 입력 136 34 38 |
예제 출력 12 4 |
예제 입력 255 17 23 14 83 |
예제 출력 23 |
풀이
주어진 숫자들을 나누어서 공통된 나머지가 나오는 수들을 구하는 문제이다.
수학적 사고가 필요한 문제였다.
A, B 라는 수가 있을 때,
A = (a * M) + rB = (b * M) + r
위와 같이 나타낼 수 있다.
여기서 나머지를 없애기 위해 인접한 수의 차를 구하면 다음과 같이 정리된다.
B - A = (b - a) * M
즉, B - A 는 M 의 배수이다.
예제 1의 6, 34, 38은 각각
6 = (a * M ) + r
34 = (b * M) + r
38 = (c * M) + r
34 - 6 = (b - a) * M
38 - 34 = (c - b) * M
28 = (b - a) * M
4 = (c - b) * M
즉 28과 4는 M의 배수라는 말이다.
괄호 안은 자연수이고 M은 두 수 모두에 적용될 수 있어야 하므로
둘의 최대공약수의 약수를 구하도록 하자.
n = int(input())
nums = [int(input()) for i in range(n)]
nums.sort()
def gcd(x,y):
if x%y == 0:
return y
return gcd(y,x % y)
# 최대공약수 함수
a = []
for i in range(1,n):
a.append(nums[i] - nums[i-1])
a.sort()
# 숫자들의 차를 담은 배열
while(len(a)!=1):
for i in range(1,len(a)):
a[i-1] = gcd(a[i],a[i-1])
a = a[:len(a)-1]
a = a[0]
# 숫자가 하나가 남을 때까지 최대공약수를 구함
result = [a]
for i in range(2,int(a**0.5)+1):
if a%i == 0:
result.append(i)
result.append(a//i)
print(*sorted(list(set(result))))
# 하나 남은 최대공약수의 약수들을 구함
'알고리즘 연습 > 정수론 및 조합론' 카테고리의 다른 글
[🥉1 / 백준 11050 / 파이썬] 이항 계수 1 (0) | 2021.06.23 |
---|---|
[🥈3 / 백준 3036 / 파이썬] 링 (0) | 2021.06.23 |
[🥈5 / 백준 1934 / 파이썬] 최소공배수 (유클리드 알고리즘) (0) | 2021.06.21 |
[🥈5 / 백준 2609 / 파이썬] 최대공약수와 최소공배수 (0) | 2021.06.21 |
[🥈5 / 백준 1037 / 파이썬] 약수 (0) | 2021.06.21 |