백준 13548 수열과 쿼리 6 JAVA 풀이 (Mo's Algorithm, 오프라인 쿼리)

2026. 4. 20. 20:23·코테(Solved.ac + Programmers)
728x90

🔗 문제 링크

https://www.acmicpc.net/problem/13548


📌 문제 개요

수열이 주어지고 여러 개의 구간 쿼리가 주어진다.
각 쿼리마다 구간 [L, R]에서 가장 많이 등장한 숫자의 등장 횟수(최빈값의 빈도)를 구해야 한다.


📌 접근 방법

이 문제는 단순히 각 구간을 매번 계산하면 시간 초과가 발생한다.

  • 각 쿼리마다 O(N) → 전체 O(N * M) → 불가능
  • 따라서 구간을 이동하면서 계산하는 Mo's Algorithm을 사용한다

Mo 알고리즘은 쿼리를 정렬한 뒤,
현재 구간을 유지하면서 조금씩 이동하며 계산하는 방식이다.


📌 핵심 아이디어

1. count 배열

count[x] = 값 x가 현재 구간에서 몇 번 등장했는지
 
 

 

2. freq 배열

freq[k] = k번 등장하는 값이 몇 개 있는지
 

핵심 포인트 : 최빈값을 빠르게 유지하기 위해 필요

 

 

3. maxFreq 유지

현재 구간에서 가장 많이 등장한 횟수

 

 

 

4. add / remove

add(x)

  • count[x] 증가
  • freq 갱신
  • maxFreq 증가 가능

remove(x)

  • count[x] 감소
  • freq 갱신
  • maxFreq 감소 필요 여부 체크

📌 처리 흐름

쿼리 입력 → Mo 정렬 (L 블록 기준) → curL, curR 초기화 → 각 쿼리 처리 → 결과 저장 → 출력
while(curL > L) add(--curL)
while(curR < R) add(++curR)
while(curL < L) remove(curL++)
while(curR > R) remove(curR--)​

📌 전체 코드

package no_13548;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;

public class No13548 {

    static class Query {
        int l, r, idx;

        public Query(int l, int r, int idx) {
            this.l = l;
            this.r = r;
            this.idx = idx;
        }
    }

    static int[] arr;
    static int[] count;   // 값별 등장 횟수
    static int[] freq;    // 등장 횟수별 개수
    static int maxFreq;
    static int sqrtN;

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        int n = Integer.parseInt(br.readLine());
        arr = new int[n];

        StringTokenizer st = new StringTokenizer(br.readLine());
        for (int i = 0; i < n; i++) {
            arr[i] = Integer.parseInt(st.nextToken());
        }

        int m = Integer.parseInt(br.readLine());
        Query[] queries = new Query[m];
        int[] answer = new int[m];

        for (int i = 0; i < m; i++) {
            st = new StringTokenizer(br.readLine());
            int l = Integer.parseInt(st.nextToken()) - 1;
            int r = Integer.parseInt(st.nextToken()) - 1;
            queries[i] = new Query(l, r, i);
        }

        sqrtN = (int) Math.sqrt(n);
        count = new int[1000001];
        freq = new int[n + 1];
        maxFreq = 0;

        Arrays.sort(queries, (a, b) -> {
            int blockA = a.l / sqrtN;
            int blockB = b.l / sqrtN;

            if (blockA != blockB) {
                return blockA - blockB;
            }
            return a.r - b.r;
        });

        int curL = 0;
        int curR = -1;

        for (Query q : queries) {
            while (curL > q.l) add(arr[--curL]);
            while (curR < q.r) add(arr[++curR]);
            while (curL < q.l) remove(arr[curL++]);
            while (curR > q.r) remove(arr[curR--]);

            answer[q.idx] = maxFreq;
        }

        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < m; i++) {
            sb.append(answer[i]).append("\n");
        }

        System.out.print(sb);
    }

    static void add(int x) {
        int c = count[x];
        freq[c]--;
        count[x]++;
        freq[c + 1]++;

        maxFreq = Math.max(maxFreq, count[x]);
    }

    static void remove(int x) {
        int c = count[x];
        freq[c]--;
        count[x]--;
        freq[c - 1]++;

        if (freq[maxFreq] == 0) {
            maxFreq--;
        }
    }
}

 


📄 정리

  • 구간 최빈값 문제 → Mo's Algorithm 필수 유형
  • count + freq 2개 배열로 최빈값 유지
  • add/remove 구현이 핵심
728x90

'코테(Solved.ac + Programmers)' 카테고리의 다른 글

백준 1149 RGB 거리 JAVA 풀이 (DP, 누적 최소값, 시간복잡도)  (0) 2026.04.24
[백준] 트리 순회 JAVA 풀이 (트리, 재귀, DFS)  (0) 2026.04.21
백준 1531 투명 JAVA 풀이 (브루트포스, 시뮬레이션)  (0) 2026.04.19
백준 2748 피보나치 수 2 JAVA 풀이 (DP, 반복문, 시간복잡도)  (0) 2026.04.16
백준 9237 이장님 초대 JAVA 풀이 (그리디, 정렬, 시간복잡도)  (0) 2026.04.15
'코테(Solved.ac + Programmers)' 카테고리의 다른 글
  • 백준 1149 RGB 거리 JAVA 풀이 (DP, 누적 최소값, 시간복잡도)
  • [백준] 트리 순회 JAVA 풀이 (트리, 재귀, DFS)
  • 백준 1531 투명 JAVA 풀이 (브루트포스, 시뮬레이션)
  • 백준 2748 피보나치 수 2 JAVA 풀이 (DP, 반복문, 시간복잡도)
PUSH → MERGE → DEPLOY
PUSH → MERGE → DEPLOY
데이터 흐름과 운영 자동화를 설계하는 백엔드 개발자
  • PUSH → MERGE → DEPLOY
    Coding Dongin
    PUSH → MERGE → DEPLOY
  • 전체
    오늘
    어제
    • MEUN N
      • 코테(Solved.ac + Programmers) N
      • BootCamp(JAVA)
      • JAVA
      • SpringBoot
      • JavaScript
      • JSP
      • DB(SQL)
      • React
      • HTML_CSS
      • jQuery
      • SCSS
      • GSAP
      • 설치 + 꿀팁
      • 정보처리기사 오답노트
      • 정보처리기사 기출문제
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

    • GIT
  • 공지사항

  • 인기 글

  • 태그

    자료구조
    구현
    실기
    수학
    문자열
    피보나치
    코딩테스트
    알고리즘
    정처기실기
    Level2
    배열
    level0
    정보처리기사
    백준
    springboot
    프로그래머스
    기출문제
    시뮬레이션
    자바
    dp
    정처기오답노트
    level1
    브루트포스
    정처기
    java
    정렬
    완전탐색
    정보처리기사 실기 기출문제
    solved.ac
    백엔드개발자
  • 최근 댓글

  • 최근 글

  • 250x250
  • hELLO· Designed By정상우.v4.10.4
PUSH → MERGE → DEPLOY
백준 13548 수열과 쿼리 6 JAVA 풀이 (Mo's Algorithm, 오프라인 쿼리)
상단으로

티스토리툴바