문제
풀이
정렬, 누적 합 문제이다.
각각의 컬러공의 크기 이하의 컬러공을 모두 탐색한다면 O(N * N)으로 시간초과이다. 컬러공을 한 번만 순회하여 문제를 해결해야 한다.
- 컬러공을 크기의 오름차순으로 정렬한다.
- 정렬한 컬러공을 처음부터 탐색하면서 현재 i까지의 크기의 합을 구한다.
- 그 합에서 지금까지 나온 공들 중에서 i번 공과 같은 색을 가진 공들을 뺀다.
- 그 합에서 지금까지 나온 공들 중에서 i번 공과 같은 무게를 가진 공들을 뺀다(크기 순으로 정렬되어 있으므로 i번 공보다 크기가 큰 공은 현재까지 합해지지 않았다).
- 이렇게 하면, i번 공과 색상과 크기가 모두 같은 공은 총 두 번 빠진다. 그러므로, 지금까지 나온 공들 중에서 i번 공과 같은 색과 같은 크기를 가진 공들은 한 번 더해줘야 올바른 답이 나올 수 있다.
- 위의 그림에서 초록색 영역이 i번째 공까지의 총 합이다. 여기서 빨간색 영역인 i번 공과 같은 색의 공들을 빼고, 파란색 영역인 i번 공과 같은 크기의 공들을 뺀다면, 하늘색 영역인 i번 공과 동일한 공들은 두 번 빼게 된다. 그러므로, 하늘색 영역은 한 번 더해줘야 한다.
코드
#include <iostream>
#include <vector>
#include <algorithm>
#include <set>
using namespace std;
typedef struct
{
int color;
int size;
int index; // 공들을 정렬할 것이므로, 정렬 전의 인덱스 좌표가 필요하다.
}ball;
vector<ball> balls;
int sum;
map<int, int> color_sum;
map<int, int> size_sum;
map<pair<int, int>, int> ball_count;
vector<int> answer;
bool compare(const ball& a, const ball& b)
{
return a.size < b.size;
}
int main()
{
ios_base::sync_with_stdio(0);
cin.tie(NULL);
cout.tie(NULL);
int N;
cin >> N;
for (int i = 0; i < N; ++i)
{
int color, size;
cin >> color >> size;
balls.push_back({ color, size, i });
}
// 공들을 크기 순으로 정렬한다.
sort(balls.begin(), balls.end(), compare);
answer.resize(N);
// 0번부터 접근하여 i번까지 공의 합을 구한다. 그 합에서 필요없는 부분을 빼는 방법으로 답을 구한다.
// 현재까지 공의 합에서 뺄 것은 다음과 같다.
// 1. 현재 색과 같은 공의 합
// 2. 현재 공과 같은 크기의 공의 합
// 이렇게 뺀다면 현재 까지 나온 공 중에서, 현재 공과 색상과 크기가 같은 공은 중복으로 빼진다.
// 그러므로, 중복으로 빠진 공은 한번 더해주어야 답이 올바르다.
for (int i = 0; i < N; ++i)
{
ball current = balls[i];
sum += current.size;
color_sum[current.color] += current.size;
size_sum[current.size] += current.size;
ball_count[make_pair(current.color, current.size)]++;
// 답을 현재 공의 정렬 전 인덱스에 넣는다.
answer[current.index] = sum - color_sum[current.color] - size_sum[current.size]
+ current.size * ball_count[make_pair(current.color, current.size)];
}
for (int i = 0; i < N; ++i)
{
cout << answer[i] << '\n';
}
return 0;
}
'알고리즘 > 백준' 카테고리의 다른 글
[백준][C++] 16139: 인간-컴퓨터 상호작용 (1) | 2023.11.20 |
---|---|
[백준][C++] 10986: 나머지 합 (2) | 2023.11.20 |
[백준][C++] 30508: 고인물이싫어 (0) | 2023.11.17 |
[백준][C++] 17822: 원판 돌리기 (0) | 2023.11.16 |
[백준][C++] 17609: 회문 (0) | 2023.11.15 |