가로 길이가 Wcm, 세로 길이가 Hcm인 직사각형 종이가 있습니다. 종이에는 가로, 세로 방향과 평행하게 격자 형태로 선이 그어져 있으며, 모든 격자칸은 1cm x 1cm 크기입니다. 이 종이를 격자 선을 따라 1cm × 1cm의 정사각형으로 잘라 사용할 예정이었는데, 누군가가 이 종이를 대각선 꼭지점 2개를 잇는 방향으로 잘라 놓았습니다. 그러므로 현재 직사각형 종이는 크기가 같은 직각삼각형 2개로 나누어진 상태입니다. 새로운 종이를 구할 수 없는 상태이기 때문에, 이 종이에서 원래 종이의 가로, 세로 방향과 평행하게 1cm × 1cm로 잘라 사용할 수 있는 만큼만 사용하기로 하였습니다.
가로의 길이 W와 세로의 길이 H가 주어질 때, 사용할 수 있는 정사각형의 개수를 구하는 solution 함수를 완성해 주세요.
W | H | result |
---|---|---|
8 | 12 | 80 |
입출력 예 #1
가로가 8, 세로가 12인 직사각형을 대각선 방향으로 자르면 총 16개 정사각형을 사용할 수 없게 됩니다. 원래 직사각형에서는 96개의 정사각형을 만들 수 있었으므로, 96 - 16 = 80 을 반환합니다.
w와 h는 1억 이하의 자연수 -> 절대로 반복문을 사용하지 말 것!
=> 수학적으로 접근해야 한다.
(질문하기 참고)
위의 그림에서 흰색 정사각형의 모양이 동일하게 반복되는 것을 볼 수 있다. 따라서 w와 h의 최소공약수로 나눈 w'와 h'로 모양을 축소할 수 있다.(즉, 아래와 같은 상태)
w' = 2, h' = 3 인 상태에서 대각선이 지나간 정사각형의 개수는 w' + h' -1 이다. 즉, 1은 2와 3의 최소공약수이고, 원래대로면 w + h - (최소공약수) 이다.
import Foundation
func solution(_ w:Int, _ h:Int) -> Int64{
return Int64(w * h - (w + h - (gcd(w, h))))
}
func gcd(_ a: Int, _ b: Int) -> Int {
return b == 0 ? a : gcd(b, a % b)
}
정확성 | 테스트 | 정확성 | 테스트 |
---|---|---|---|
테스트 1 〉 | 통과 (0.01ms, 16.2MB) | 테스트 2 〉 | 통과 (0.02ms, 16.1MB) |
테스트 3 〉 | 통과 (0.01ms, 16.2MB) | 테스트 4 〉 | 통과 (0.02ms, 16.2MB) |
테스트 5 〉 | 통과 (0.02ms, 16.2MB) | 테스트 6 〉 | 통과 (0.02ms, 16.1MB) |
테스트 7 〉 | 통과 (0.01ms, 16.2MB) | 테스트 8 〉 | 통과 (0.01ms, 16.2MB) |
테스트 9 〉 | 통과 (0.01ms, 16.3MB) | 테스트 10 〉 | 통과 (0.01ms, 16.4MB) |
테스트 11 〉 | 통과 (0.01ms, 16.4MB) | 테스트 12 〉 | 통과 (0.01ms, 16.1MB) |
테스트 13 〉 | 통과 (0.01ms, 16.3MB) | 테스트 14 〉 | 통과 (0.01ms, 16.2MB) |
테스트 15 〉 | 통과 (0.01ms, 16.4MB) | 테스트 16 〉 | 통과 (0.01ms, 16.2MB) |
테스트 17 〉 | 통과 (0.01ms, 16.4MB) | 테스트 18 〉 | 통과 (0.02ms, 16.2MB) |
import Foundation
func gcd(_ a:Int, _ b:Int) -> Int64{
if a == 0 { return Int64(b) }
return gcd(b%a,a)
}
func solution(_ w:Int, _ h:Int) -> Int64{
var w64:Int64 = Int64(w)
var h64:Int64 = Int64(h)
return w64*h64-w64-h64+gcd(w,h)
}
정확성 | 테스트 | 정확성 | 테스트 |
---|---|---|---|
테스트 1 〉 | 통과 (0.01ms, 16.1MB) | 테스트 2 〉 | 통과 (0.01ms, 16.2MB) |
테스트 3 〉 | 통과 (0.01ms, 16.1MB) | 테스트 4 〉 | 통과 (0.01ms, 16.4MB) |
테스트 5 〉 | 통과 (0.01ms, 16.3MB) | 테스트 6 〉 | 통과 (0.01ms, 16.3MB) |
테스트 7 〉 | 통과 (0.01ms, 16.2MB) | 테스트 8 〉 | 통과 (0.01ms, 16MB) |
테스트 9 〉 | 통과 (0.01ms, 16.2MB) | 테스트 10 〉 | 통과 (0.01ms, 16MB) |
테스트 11 〉 | 통과 (0.01ms, 16.5MB) | 테스트 12 〉 | 통과 (0.01ms, 16.1MB) |
테스트 13 〉 | 통과 (0.01ms, 16.2MB) | 테스트 14 〉 | 통과 (0.01ms, 16.1MB) |
테스트 15 〉 | 통과 (0.01ms, 16.1MB) | 테스트 16 〉 | 통과 (0.01ms, 16.4MB) |
테스트 17 〉 | 통과 (0.01ms, 16.2MB) | 테스트 18 〉 | 통과 (0.01ms, 16.3MB) |
이번 문제는 for 문이 나 while 문을 사용하면 시간 초과될 가능성이 있는 문제라는 걸 알고 수학적으로 접근해 보려고 했다.
문제에 직각삼각형이 언급돼서 빗변 길이와 연관되어 있는 줄 알고 시도해 봤지만 틀렸고, 결국 질문하기에서 힌트를 얻어서 문제를 해결했다. 최소 공약수와 관련되었을 줄은 상상도 못했다.
최소 공약 수하면 유명한 GCD 알고리즘은 꼭 알고 있자.