Algorithm/Baekjoon

[Baekjoon 백준] 10986 나머지 합 - Java

뭐든 해보기 2023. 1. 27. 20:21

문제) 수 N개 A1, A2, ..., AN이 주어진다.

이때, 연속된 부분 구간의 합이 M으로 나누어 떨어지는 구간의 개수를 구하는 프로그램을 작성하시오.

즉, Ai + ... + Aj (i ≤ j) 의 합이 M으로 나누어 떨어지는 (i, j) 쌍의 개수를 구해야 한다.

 

입력) 첫째 줄에 N과 M이 주어진다. (1 ≤ N ≤ 10^6, 2 ≤ M ≤ 10^3)

둘째 줄에 N개의 수 A1, A2, ..., AN이 주어진다. (0 ≤ Ai ≤ 10^9)

 

출력) 첫째 줄에 연속된 부분 구간의 합이 M으로 나누어 떨어지는 구간의 개수를 출력한다.


1. 변수 선언

2. 수열 구간 합 배열, 구간 합 나머지 배열 선언

3. 구간 합 계산

4. 구간 합 나머지 계산

5. 경우의 수 판단하여 최종 값에 더하기

 

public static void main(String[] args) throws IOException {
		// TODO Auto-generated method stub
		//System.setIn(new FileInputStream("src/baekjoon/code10986"));
		Scanner sc = new Scanner(System.in);
		int N = sc.nextInt(); //수열 개수
		int M = sc.nextInt();  //나눌 수
		long[] S = new long[N]; // 수열의 구간 합 배열
		long[] C = new long[M]; // 구간 합의 나머지 배열
		long answer = 0; //질의 답
		S[0] = sc.nextInt(); 
		// 구간 합 계산
		for (int i = 1; i < N; i++) {
			S[i] = S[i - 1] + sc.nextInt();
		}
		//구간 합 나머지 계산
		for(int i=0; i<N; i++) {
			int rm = (int) (S[i] % M);
			//0~i 구간 합의 나머지가 0일 때 정답 count
			if(rm == 0) answer++; 
			//나머지가 같은 인덱스 개수 count
			C[rm]++;
		}
		
		for(int i=0; i<M; i++) {
			if(C[i]>1) {
				//나머지가 같은 인덱스 중 2가지를 뽑는 경우의 수 더하기
				answer = answer + (C[i]*(C[i]-1)/2);
			}
		}
		System.out.println(answer);
	}

 

 

  • 특정 구간 수들의 나머지 연산을 더해 나머지 연산을 한 값과 이 구간 합의 나머지 연산을 한 값은 동일하다.
  • 구간 합 배열을 이용한 식 S[i] - S[j]는 원본 배열의 j + 1 부터 i까지의 구간 합이다.
  • S[i] % M 의 값과 S[j] % M의 값이 같다면 (S[i]-S[j]) % M은 0이다. 즉, 구간 합 배열의 원소를 M으로 나눈 나머지로 업데이트 하고 S[i]와 S[j]가 같은 (i,j)쌍을 찾으면 원본 배열에서 j + 1 부터 i 까지의 구간 합이 M으로 나누어 떨어진다는 것을 알 수 있다.