목차
문제 : boj17436
필요 알고리즘
- 포함 배제의 원리 (inclusion and exclusion)
- 포함 배제의 원리로 풀 수 있는 문제이다.
※ 제 코드에서 왜 main 함수에 로직을 직접 작성하지 않았는지, 왜 Scanner를 쓰지 않고 BufferedReader를 사용했는지 등에 대해서는 '자바로 백준 풀 때의 팁 및 주의점' 글을 참고해주세요. 백준을 자바로 풀어보려고 시작하시는 분이나, 백준에서 자바로 풀 때의 팁을 원하시는 분들도 보시는걸 추천드립니다.
풀이
예제 입력 2를 생각해보자.
2 100
2 3
직관적으로 우린 이걸 푸는 방법을 알고 있다. 100 이하의 자연수 중 2로 나누어 떨어지는 수는 100/2 = 50개가 존재한다. 그리고 3으로 나누어떨어지는건 100/3 = 33개가 존재한다. 그리고 둘이 중복으로 세어버린 100/(2x3) = 16개는 빼줘야한다. 최종적으로 50 + 33 - 16 = 67이 답이다.
3개라면 어떨까? 주어진 소수가 A, B, C 라고 한다면
100/A + 100/B + 100/C - 100/(AB) - 100/(BC) - 100/(AC) + 100/(ABC) 가 될 것이다.
이걸 일반화해서 4개, 5개, ... 에 대해서도 정의한게 포함 배제의 원리이다. 결론적으로 그냥 홀수 개의 교집합은 더하고, 짝수 개의 교집합은 빼면 된다.
long answer = 0l;
for (int i = 1; i <= n; i++) {
long tmp = solve(-1, i, 1); // i개의 교집합으로 셀 수 있는 경우의 수
if (i%2==1) answer+=tmp; // 홀수 교집합이면 더하고
else answer-=tmp; // 짝수 교집합이면 뺀다
}
System.out.println(answer);
개념적인 부분 보다는 재귀를 안쓰면 상당히 코드가 복잡해지므로 특정 x개의 교집합을 만드는 부분에서 구현이 좀 어려울 순 있다. 재귀가 익숙하지 않다면 디버깅을 걸어서 한번 어떤식으로 동작하는지 한 단계씩 생각해보자. 그리고 이 문제는 모든 입력값이 모두 다르고, 소수라서 별 문제 없었는데 그게 아니라면 좀 더 귀찮아진다.
private long solve(final int bf, final int cnt, final long mult) {
if (cnt == 0) {
return m/mult;
}
long result = 0l;
for (int i = bf+1; i <= n-cnt; i++) {
result += solve(i, cnt-1, mult*arr[i]);
}
return result;
}
코드 : github
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
public class Main {
private static BufferedReader br = new BufferedReader(new InputStreamReader(System.in), 1 << 16);
public static void main(String[] args) throws Exception {
new Main().solution();
}
private long[] arr;
int n;
long m;
public void solution() throws Exception {
StringTokenizer st = new StringTokenizer(br.readLine());
n = Integer.parseInt(st.nextToken());
m = Long.parseLong(st.nextToken());
arr = new long[n];
st = new StringTokenizer(br.readLine());
for (int i = 0; i < n; i++) {
arr[i] = Long.parseLong(st.nextToken());
}
long answer = 0l;
for (int i = 1; i <= n; i++) {
long tmp = solve(-1, i, 1);
if (i%2==1) answer+=tmp;
else answer-=tmp;
}
System.out.println(answer);
}
private long solve(final int bf, final int cnt, final long mult) {
if (cnt == 0) {
return m/mult;
}
long result = 0l;
for (int i = bf+1; i <= n-cnt; i++) {
result += solve(i, cnt-1, mult*arr[i]);
}
return result;
}
}
'PS > BOJ' 카테고리의 다른 글
[자바] 백준 1953 - 팀배분 (java) (0) | 2024.02.26 |
---|---|
[자바] 백준 16935 - 배열 돌리기 3 (java) (0) | 2024.02.26 |
[자바] 백준 24956 - 나는 정말 휘파람을 못 불어 (java) (0) | 2024.02.24 |
[자바] 백준 16563 - 어려운 소인수분해 (java) (0) | 2024.02.23 |
[자바] 백준 3142 - 즐거운 삶을 위한 노력 (java) (0) | 2024.02.23 |
댓글