문제 : https://www.acmicpc.net/problem/2912
1.
기본적인 아이디어는 각 쿼리의 [a, b] 구간에 대해 매번 [a, b] 전체를 확인하지 않고, 이전에 확인했던 구간과 겹치는 구간은 제외하고 확인하는 것이다. 예를들어 이전에 확인했던 구간이 [1, 100]이고 이번에 확인할 구간이 [4, 95]라고 해보자.
이 때, [1, 100] 구간을 전부 확인하면 100번 + [4, 95] 구간을 전부 확인하면 92번 봐야 한다. 그럼 192번 동작해야 한다. 하지만 [1, 100] 구간의 결과에서 [1, 3] 구간을 빼고, [96, 100] 구간을 빼면 [4, 95] 구간 전체를 본 것과 동일한 결과를 얻을 수 있다. 이 경우 108번만 동작하면 된다.
2.
update가 없는 쿼리 문제이다. 따라서 쿼리 순서를 효율적으로 변경해 풀어도 된다. (offline query)
[a, b] 사이의 값들에 대한 구간 쿼리 이므로, '1'의 아이디어를 적용하여 쿼리의 순서를 최대한 이전과 많은 구간이 겹치게 하면 효율적으로 풀 수 있다. 이전과 최대한 많은 구간을 겹치게 쿼리의 순서를 바꾸는 것은 모스(Mo's) 알고리즘의 방식을 사용하면 된다. 'a / sqrt(n)'로 정렬 후 동일하다면 'b'로 정렬
3.
색상 최대치가 10000개 뿐이므로, 10000 크기의 배열에 모자 색상을 카운팅한다면, k/2보다 많은 색상의 모자는 단순히 각 쿼리마다 전체 배열을 확인해도 딱히 문제 없다. (O(10000*10000) -> 코드의 'getHatNum()'
코드 : https://github.com/NaHwaSa/BOJ_BaekjunOnlineJudge/blob/master/02900/BOJ_2912.java
import java.io.DataInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
class Picture implements Comparable<Picture> {
int a, b, order;
static int sqrtN;
public Picture(int a, int b, int order) {
this.a = a;
this.b = b;
this.order = order;
}
@Override
public int compareTo(Picture o) {
int a1 = this.a / sqrtN;
int a2 = o.a / sqrtN;
if (a1 == a2) return this.b - o.b;
return a1-a2;
}
}
public class Main extends FastInput {
private int getHatNum(int[] cnt, Picture cur) {
int target = (cur.b-cur.a+1)/2;
for (int i = 1; i < cnt.length; i++) {
if (cnt[i] > target) return i;
}
return -1;
}
private void solution() throws Exception {
int n = nextInt();
Picture.sqrtN = (int) Math.sqrt(n);
int c = nextInt();
int[] arr = new int[n+1];
for (int i = 1; i <= n; i++)
arr[i] = nextInt();
int m = nextInt();
int[] answer = new int[m];
ArrayList<Picture> pic = new ArrayList<>();
for (int i = 0; i < m; i++) {
pic.add(new Picture(nextInt(), nextInt(), i));
}
Collections.sort(pic);
int[] cnt = new int[c+1];
for (int i = pic.get(0).a; i <= pic.get(0).b; i++) {
++cnt[arr[i]];
}
answer[pic.get(0).order] = getHatNum(cnt, pic.get(0));
for (int idx = 1; idx < pic.size(); idx++) {
int curA = pic.get(idx).a;
int curB = pic.get(idx).b;
int befA = pic.get(idx-1).a;
int befB = pic.get(idx-1).b;
for (int i = befA; i < curA; i++) cnt[arr[i]]--;
for (int i = curA; i < befA; i++) cnt[arr[i]]++;
for (int i = befB+1; i <= curB; i++) cnt[arr[i]]++;
for (int i = curB+1; i <= befB; i++) cnt[arr[i]]--;
answer[pic.get(idx).order] = getHatNum(cnt, pic.get(idx));
}
StringBuilder output = new StringBuilder();
for (int i = 0; i < m; i++) {
if (answer[i] == -1) output.append('n').append('o');
else output.append('y').append('e').append('s').append(' ').append(answer[i]);
output.append('\n');
}
System.out.print(output);
}
public static void main(String[] args) throws Exception {
initFI();
new Main().solution();
}
}
class FastInput {
private static final int DEFAULT_BUFFER_SIZE = 1 << 16;
private static DataInputStream inputStream;
private static byte[] buffer;
private static int curIdx, maxIdx;
protected static void initFI() {
inputStream = new DataInputStream(System.in);
buffer = new byte[DEFAULT_BUFFER_SIZE];
curIdx = maxIdx = 0;
}
protected static int nextInt() throws IOException {
int ret = 0;
byte c = read();
while (c <= ' ') c = read();
do {
ret = ret * 10 + c - '0';
} while ((c = read()) >= '0' && c <= '9');
return ret;
}
private static byte read() throws IOException {
if (curIdx == maxIdx) {
maxIdx = inputStream.read(buffer, curIdx = 0, DEFAULT_BUFFER_SIZE);
if (maxIdx == -1) buffer[0] = -1;
}
return buffer[curIdx++];
}
}
'PS > BOJ' 카테고리의 다른 글
백준 5966 자바 - Cow Cotillion (BOJ 5966 JAVA) (0) | 2021.11.23 |
---|---|
백준 21187 자바 - Pulling Their Weight (BOJ 21187 JAVA) (0) | 2021.11.22 |
백준 14897 자바 - 서로 다른 수와 쿼리 1 (BOJ 14897 JAVA) (0) | 2021.11.19 |
백준 10542 자바 - 마피아 게임 (BOJ 10542 JAVA) (0) | 2021.11.18 |
백준 16509 자바 - 장군 (BOJ 16509 JAVA) (0) | 2021.11.18 |
댓글