Closed MUKER-WON closed 2 months ago
1과 자신으로만 나눠지는 수 즉 약수가 2개인 수를 말한다. 2부터 n-1까지의 수로 나누어지지 않는 수
1은 소수가 아니다.
합성수 1과 자기 자신을 제외한 다른 약수를 가지고 있는 수
연산이 최대 n-2번 발생하기때문에 시간복잡도는 O(n) 이 시간복잡도를 O(sqrt(n))으로 줄일 수 있는 방법이 있다
합성수 N에서 1을 제외한 가장 작은 약수는 sqrt(N) 이하이다. N이 9라면, sqrt(9)는 3이다. 가장 작은약수는 3이하고 1,3,9중 1을 제외한 가장 작은 약수는 3이 됨
따라서 2부터 n-1까지의 수로 나누어지지 않는 수를 지금까지 소수라고 했다면 O(n) 2부터 sqrt(n)까지의 수로 나누어지지 않으면 소수이다. O(sqrt(n))
1978: 소수찾기
소수
합성수
sqrt()
함수를 사용하면 안될까?sqrt()
는 실수 연산을 하기 때문에 정수형 계산을 정확히 다루는 문제에서 조심해야 할 부분이 있다. 이유는 Double 타입을 반환하므로 소수점이 포함되어 실수 오차로 인해 정밀한 정수 계산이 필요할 때 문제가 발생할 수 있기 때문이다.sqrt()
를 사용하는 것은 유용하다.func sieveOfEratosthenes(_ n: Int) -> [Int] {
// 0부터 n까지의 값을 가진 배열을 true로 초기화 (소수인지 여부를 나타냄)
var isPrime = [Bool](repeating: true, count: n + 1)
isPrime[0] = false // 0은 소수가 아님
isPrime[1] = false // 1도 소수가 아님
// 2부터 sqrt(n)까지의 수들에 대해
for i in 2...Int(Double(n).squareRoot()) {
if isPrime[i] {
// i의 배수들을 소수가 아니라고 표시
for multiple in stride(from: i * i, through: n, by: i) {
isPrime[multiple] = false
}
}
}
// 소수인 수들만 배열로 반환
return (2...n).filter { isPrime[$0] }
}
let primes = sieveOfEratosthenes(50)
print(primes)
import Foundation
func optimizedPrimeFactorization(_ n: Int) {
var n = n
// 먼저 2로 나누기
while n % 2 == 0 {
print(2)
n /= 2
}
// 3부터는 홀수만 체크 (i += 2)
var i = 3
while i * i <= n {
while n % i == 0 {
print(i)
n /= i
}
i += 2
}
// n이 1보다 크면 마지막 소수 출력
if n > 1 {
print(n)
}
}
let n = Int(readLine()!)!
optimizedPrimeFactorization(n)
GCD(a, b) = GCD(b, a % b)
가 된다.func gcd(_ a: Int, _ b: Int) -> Int {
return a == 0 ? b : gcd(b % a, a)
}
A * B = GCD(A, B) * LCM(A, B)
가 성립이 되기에 해당 코드로 구현할 수 있다.func lcm(_ a: Int, _ b: Int) -> Int {
return (a * b) / gcd(a, b)
}
// 오버플로우가 걱정된다면 해당 코드로 구현 가능
func lcm(_ a: Int, _ b: Int) -> Int {
return a / gcd(a, b) * b
}
// 모듈로 역수를 구하는 함수
func modInverse(_ a: Int, _ m: Int) -> Int {
var m0 = m
var y = 0, x = 1
if m == 1 {
return 0
}
var a = a
while a > 1 {
let q = a / m
var t = m
m = a % m
a = t
t = y
y = x - q * y
x = t
}
if x < 0 {
x += m0
}
return x
}
// 중국인의 나머지 정리 함수
func chineseRemainder(_ nums: [Int], _ rems: [Int]) -> Int {
let prod = nums.reduce(1, *)
var result = 0
for i in 0..<nums.count {
let pp = prod / nums[i]
result += rems[i] * modInverse(pp, nums[i]) * pp
}
return result % prod
}
// 테스트 예시
let nums = [3, 5, 7] // 모듈로들
let rems = [2, 3, 2] // 나머지들
let result = chineseRemainder(nums, rems)
print("\(result)")
// 재귀적으로 이항계수 계산
func BCR(n: Int, k: Int) -> Int {
if k == 0 || k == n { return 1 }
return BCR(n: n - 1, k: k - 1) + BCR(n: n - 1, k: k)
}
// 예시
let resultRecursive = BCR(n: n, k: k)
print("C(\(n), \(k)) = \(resultRecursive)") // 출력: C(5, 2) = 10
dp[i][j] = dp[i-1][j-1] + dp[i-1][j]
이기에 dp배열을 만들고 메모제이션 해주면 된다.let I = readLine()!.split { $0 == " " }.map { Int($0)! }
let (N,K) = (I[0],I[1])
var dp = Array(repeating: Array(repeating: 0, count: N+1), count: N+1)
for i in 0...N {
for j in 0...min(i,K) { // 불필요한 반복을 줄이기 위해 i,k중 작은값 까지 반복
if j == 0 || j == i { dp[i][j] = 1 }
else { dp[i][j] = (dp[i-1][j-1] + dp[i-1][j]) % 10007 }
}
}
print(dp[N][K])
import Foundation
let inputNum = Int(readLine()!)!
func solution(M: Int, N: Int, x: Int, y: Int) -> Int {
let lcm = lcm(M, N)
var year = x
while year <= lcm {
if (year - 1) % N + 1 == y {
return year
}
year += M
}
return -1
}
func gcd(_ a: Int, _ b: Int) -> Int {
return b == 0 ? a : gcd(b, a % b)
}
func lcm(_ a: Int, _ b: Int) -> Int {
return a / gcd(a, b) * b
}
let result: [Int] = (0..<inputNum).map { _ in
let input = readLine()!.components(separatedBy: " ").compactMap { Int($0) }
return solution(M: input[0], N: input[1], x: input[2], y: input[3])
}
result.forEach {
print($0)
}
루트 N 범위를 잡을 때 루트 연산자를 쓰면 실수 연산자라 오차가 발생할 수 있음
for 문의 조건에서 i*i<=N
이라고 두면 됌
import Foundation
var n = Int(readLine()!)!
var i = 3
func division() {
guard n > 1 else { return }
while n%2 == 0 {
print("2")
n /= 2
}
while i*i<=n {
if n%i==0 {
print(i)
n /= i
} else {
i += 2
}
}
if n > 1 {
print(n)
}
}
division()
수학 문제는 많이 나오지 않지만, 기본 개념을 숙지할 것
소수는 1과 자기 자신으로만 나누어지는 수이다. 합성수에서 1을 제외한 가장 작은 약수는 √N 이하이므로, 소수를 구할 때 N-1까지 나누지 않고 √N까지만 나누어도 소수인지 판단할 수 있다.
2부터 N까지의 소수를 구하는 알고리즘으로, 배수를 제거하는 방식이다. 소수를 빠르게 구할 수 있는 방법으로 사용된다.
정수를 소수의 곱으로 나타내는 것을 의미한다. 예를 들어, 1100 = 2 2 5 5 11로 표현된다.
두 자연수의 공통된 약수 중 가장 큰 약수로, 유클리드 호제법을 사용하여 구할 수 있다.
두 자연수의 공통 배수 중 가장 작은 수로, GCD를 이용하여 LCM을 구할 수 있다.
여러 개의 합동식을 동시에 만족하는 값을 구하는 문제이다. 중국인의 나머지 정리를 통해 해를 구할 수 있으며, 모듈로 값들이 서로소일 때 유용하다.
n개의 원소 중 k개의 원소를 선택하는 방법의 수를 나타낸다. 이항계수는 재귀 함수나 파스칼의 법칙을 이용해 계산할 수 있다.
9/25 링크