※ 글쓴이는 취미로 코딩을 익혀보는 사람이라 정확하지 않은 내용을 담고 있을 수 있다 ※
이번에 볼 문제는 백준 3673번 문제인 나눌 수 있는 부분 수열이다.
문제는 아래 링크를 확인하자.
https://www.acmicpc.net/problem/3673
3673번: 나눌 수 있는 부분 수열
양의 정수로 이루어진 수열이 주어졌을 때, 연속하는 부분 수열의 합이 d로 나누어 떨어지는 것의 개수를 구하는 프로그램을 작성하시오. 예를 들어, 아래와 같은 수열의 부분 수열 중 4로 나누
www.acmicpc.net
모든 부분합을 다 살피는 것은 O(min(dN, N^2))에 해낼 수 있는데, 이는 이 문제를 해결하기에는 부족한 시간복잡도이다.
연속하는 부분 수열의 합에 대한 것을 알고싶은 문제이므로, prefix sum을 구해 문제를 풀어보자.
i번째 항부터 j번째 항까지의 합이 d로 나누어떨어진다는 말은 초항부터 i-1번째 항까지의 합과 초항부터 j번째 항까지의 합의 차가 d의 배수라는 뜻이므로, 둘을 각각 d로 나눈 나머지는 같다는 것을 알 수 있다.
따라서, prefix sum의 d로 나눈 나머지를 구해나가면서, d로 나눈 나머지가 같은 숫자들의 쌍의 개수를 세는 것으로 문제를 해결할 수 있다.
단, 초항부터 i번항까지의 합이 d의 배수라면 그 구간합 자체도 답의 하나이므로 다른 경우와 다르게 처리해야한다는 점에 유의하자.
아래는 제출한 소스코드이다.
#include <iostream>
#include <cstring>
using namespace std;
typedef long long ll;
int cnt[1000000];
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
int T; cin >> T;
while (T--) {
memset(cnt, 0, sizeof(cnt));
cnt[0]++;
ll ans = 0;
int mod, N; cin >> mod >> N;
int total = 0;
while (N--) {
int x; cin >> x;
total += x;
total %= mod;
ans += cnt[total]++;
}
cout << ans << '\n';
}
}
728x90
'BOJ' 카테고리의 다른 글
[BOJ 2513 // C++] 통학버스 (0) | 2021.12.23 |
---|---|
[BOJ 11049 // C++] 행렬 곱셈 순서 (0) | 2021.12.22 |
[BOJ 1743 // C++] 음식물 피하기 (0) | 2021.12.20 |
[BOJ 5567 // C++] 결혼식 (0) | 2021.12.19 |
[BOJ 16306 // C++] Cardboard Container (0) | 2021.12.18 |