백준

10986번 (gold 3)

이야기prog 2025. 1. 9. 23:34

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

구간합 알고리즘을 사용하는 문제중 골드문제로 어려운 축에 속한다.

 

#include <iostream>
#include <vector>

using namespace std;
int main() {

	long N, mod;
	cin >> N >> mod;
	vector<long> arr_sum(N + 1, 0);
	vector<long> mod_count(mod, 0);
	long count = 0;

	for (int i = 1; i <= N; ++i) {
		long temp;
		cin >> temp;
		arr_sum[i] = arr_sum[i - 1] + temp;
	}

	for (int i = 1; i <= N; ++i) {
		mod_count[arr_sum[i] % mod]++;
		if (arr_sum[i] % mod == 0) {
			count++;
		}
	}
	for (int i = 0; i < mod; ++i) {
		long tmp = mod_count[i];
		count += (tmp * (tmp - 1)) / 2;
	}

	cout << count;
	return 0;
}

 mod 연산과 조합공식을 이해하고 문제를 풀면 조금 더 쉬운데, 구간합에 나머지 연산 즉 모듈러 연산을 적용해서 나머지가 0이면 그 구간이 나누어 떨어지는 곳이기 때문에, 그 만큼 count를 더하고 추가로 각각의 구간합의 나머지 연산이 같다면, 예를들어 예제 입력에서 

5 3

1 2 3 1 2를 입력하면 7이 출력된다는데, 1 2 3 1 2를 컨테이너 안에 구간합을 저장해 놓는다면

arr_sum[1] == 1, arr_sum[2] == 2 + arr_sum[1], arr_sum[3] == 3 + arr_sum[2], arr[4] == 1 + arr_sum[3],

arr[5] == 2 + arr_sum[4]이고, arr_sum[i] % m == 0이라면, 그 구간합은 나누어 떨어지기 때문에 count++가 된다.

 

 또 arr_sum에 모든 요소에 예제에 있는 m 즉 3을 나누면 1 3 6 7 9 --> 1 0 0 1 0 이 되는데 저 다섯구간에서 같은 나머지를 가지는 구간들의 사이 구간합은 3으로 나누어 떨어진다고 생각할 수 있는데, 

(a - b) % m = ((a % m) - (b % m)) % m 이기 때문이다. 이산수학의 지식이 조금 필요함.

 

 즉 1하고 7사이의 구간합은 6이고 6 % 3 = ((1 % 3) - (7 % 3)) % 3 = 0이다. 즉 구간합에 나머지 연산을 한 값이 같은 구간들의 사이 구간합은 나머지 값이 0이 된다!

그래서 1 0 0 1 0 에서 1이 2개, 0이 3개인데, 1이 2개중 2개를 뽑는 경우의 수 2C2와 3개의 0중 2개를 뽑는 경우의 수

3C2를 count에 추가로 더해주면 된다!

'백준' 카테고리의 다른 글

1940번 (silver 4)  (0) 2025.01.11
2018번 (silver5)  (0) 2025.01.11
11660번 (silver 1)  (0) 2025.01.09
11659번 (Silver 3)  (0) 2025.01.09
백준 3190번(Gold 4)  (1) 2023.11.22