| 문제 정보 백준 10986번 나머지 합 https://www.acmicpc.net/problem/10986 |
문제
수 N개 A1, A2, ..., AN이 주어진다. 이때, 연속된 부분 구간의 합이 M으로 나누어 떨어지는 구간의 개수를 구하는 프로그램을 작성하시오.
즉, Ai + ... + Aj (i ≤ j) 의 합이 M으로 나누어 떨어지는 (i, j) 쌍의 개수를 구해야 한다.
입력
첫째 줄에 N과 M이 주어진다. (1 ≤ N ≤ 106, 2 ≤ M ≤ 103)
둘째 줄에 N개의 수 A1, A2, ..., AN이 주어진다. (0 ≤ Ai ≤ 109)
출력
첫째 줄에 연속된 부분 구간의 합이 M으로 나누어 떨어지는 구간의 개수를 출력한다.
예제 입력 1
5 3
1 2 3 1 2
예제 출력 1
7
//내 코드
#include<iostream>
#include<vector>
using namespace std;
int main(){
ios::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
int n, m;
long cnt=0;
cin >> n >> m;
vector<long> s(n, 0);
vector<long> a(m, 0);
cin >> s[0];
for(int i=1; i<n; i++){
int t;
cin >> t;
s[i] = s[i-1] + t;
}
for(int i=0; i<n; i++){
int r = s[i] % m;
if(r == 0) cnt++;
a[r]++;
}
for(int i=0; i<m; i++){
if(a[i] > 1)
cnt = cnt + (a[i] * (a[i]-1) / 2);
}
cout << cnt;
}
//정답 코드
#include <iostream>
#include <vector>
using namespace std;
int main()
{
ios::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
int N, M;
cin >> N >> M;
vector<long> S(N, 0);
vector<long> C(M, 0);
long answer = 0;
cin >> S[0];
for (int i = 1; i < N; i++)
{
int temp = 0;
cin >> temp;
S[i] = S[i - 1] + temp;
}
for (int i = 0; i < N; i++) { // 합 배열의 모든 값에 % 연산 수행하기
int remainder = S[i] % M;
// 0 ~ i까지의 구간 합 자체가 0일 때 정답에 더하기
if (remainder == 0) answer++;
// 나머지가 같은 인덱스의 개수 카운팅하기
C[remainder]++;
}
for (int i = 0; i < M; i++) {
if (C[i] > 1) {
// 나머지가 같은 인덱스 중 2개를 뽑는 경우의 수를 더하기
answer = answer + (C[i] * (C[i] - 1) / 2);
}
}
cout << answer << "\n";
}
문제가 쉬워 보였지만 시간 제한이 1초이기에 최적의 알고리즘을 찾아야 했고 이 점이 매우 어려웠다.
입력 값이
5 3
1 2 3 1 2
이렇다면 경우의 수는 총 7가지 이다.
1. {1, 2}
2. {1, 2, 3}
3. {1, 2, 3, 1, 2}
4. {2, 3, 1}
5. {3}
6. {3, 1, 2}
7. {1, 2}
이를 코드로 작성 한다면 크게 2가지 파트로 나누어야 한다.
첫 번째 : 합 배열 S를 만들고 M으로 나머지 연산을 수행한다. 그렇게 한다면 아래의 배열이 나온다.
{1, 3, 6, 7, 9} -> (1, 0, 0, 1, 0}
여기서 나머지가 0인 값이 3개이니 정답에 3개를 추가한다.
두 번째 : 나머지 값이 같은 원소 중 2개의 원소를 뽑는 경우의 수를 구한다.
쉽게 설명 하자면 합 배열에서 나머지 값이 1인 0번, 3번 원소가 있다. 이 두 원소의 차를 구하면 나머지가 0인 수가 나온다.
2개를 뽑는 경우의 수는 조합을 사용한다.
즉 나머지가 1인 원소에서의 경우의 수 1개, 나머지가 0인 원소에서의 경우의 수 3개
총 7개의 경우의 수가 나온다.

'Do it! 알고리즘 코딩테스트 C++' 카테고리의 다른 글
| Do it! 알고리즘 코딩테스트 | 1. 자료구조 - 투 포인터 | 007 주몽의 명령 (0) | 2025.11.26 |
|---|---|
| Do it! 알고리즘 코딩테스트 | 1. 자료구조 - 투 포인터 | 006 연속된 자연수의 합 구하기 (0) | 2025.11.26 |
| Do it! 알고리즘 코딩테스트 | 1. 자료구조 - 구간 합 | 004 구간 합 구하기 2 (0) | 2025.11.25 |
| Do it! 알고리즘 코딩테스트 | 1. 자료구조 - 구간 합 | 003 구간 합 구하기 1 (0) | 2025.11.25 |
| Do it! 알고리즘 코딩테스트 | 1. 자료구조 - 배열과 리스트 | 002 평균 구하기 (0) | 2025.11.25 |