일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 | 31 |
- 뒤집기 3
- 백준 1464
- 그래프이론
- 비트마스킹
- union find
- 재귀
- parametric search
- 최장길이바이토닉수열
- 깊이 우선 탐색
- 서로소 집합
- 2493 백준
- disjoint set
- DP
- 결정 문제
- bfs
- 브루트포스
- 패스트캠퍼스
- 백준 뒤집기 3
- 결정문제
- Lis
- 이분 탐색
- 구현
- 최장증가수열
- 이분탐색
- 그래프탐색
- 그래프 이론
- 그래프 탐색
- 분할정복
- boj 1464
- 1939백준
- Today
- Total
알고리즘 문제풀이
[BOJ] 10090 번 - Counting Inversions 본문
10090번 - Counting Inversions
시간제한 | 메모리 제한 | 제출 | 정답 | 맞은 사람 | 정답 비율 |
---|---|---|---|---|---|
1 초 | 256 MB | 1690 | 673 | 458 | 39.585% |
문제
A permutation of integers from 1 to n is a sequence a1, a2, ..., an, such that each integer from 1 to n is appeared in the sequence exactly once.
Two integers in а permutation form an inversion, when the bigger one is before the smaller one.
As an example, in the permutation 4 2 7 1 5 6 3, there are 10 inversions in total. They are the following pairs: 4–2, 4–1, 4–3, 2–1, 7–1, 7–5, 7–6, 7–3, 5–3, 6–3.
Write program invcnt that computes the number of the inversions in a given permutation.
입력
The value for the number n is written on the first line of the standard input. The permutation is written on the second line: n numbers, delimited by spaces. (2 ≤ n ≤ 1000000)
출력
Write the count of inversions on the standard output.
예제 입력 1
7
4 2 7 1 5 6 3
예제 출력 1
10
출처
https://www.acmicpc.net/problem/10090
10090번: Counting Inversions
A permutation of integers from 1 to n is a sequence a1, a2, ..., an, such that each integer from 1 to n is appeared in the sequence exactly once. Two integers in а permutation form an inversion, when the bigger one is before the smaller one. As an example
www.acmicpc.net
알고리즘 분류
- 분할정복
- 세그먼트 트리
접근 방법
처음 이 문제를 해결했을 때, "앗!" 하는 느낌이 들었는데 이제서야 복습 겸 풀이 하고자 한다.
먼저, 해당 문제를 해결할 수 있는 방법은 여러방법이 있겠지만 분할정복으로 풀고자 함을 밝힌다.
핵심은 ${i > j 인 i,j에 대해 arr_i > arr_j}$ 의 개수를 찾는 것이다.
먼저, 전체구간 [l,r] 을 구간 left = [ l, m ] & right = [ m+1, r ] 로 분할을 해보자.
그렇게 분할을 계속하다가 분할된 구간[l, r]의 크기가 1일 때 분할을 멈추고 카운팅을 시작한다.
카운팅을 할 때, 오른쪽 구간에 있는 원소가 왼쪽 구간에 있는 원소보다 인덱스가 더 크다는 것은 자명하다. 그러므로, left 구간에 있는 원소와 right 구간에 있는 원소를 비교하여 right 구간의 원소보다 큰 left 구간의 원소를 더하는 것으로 구현은 가능하다.
하지만, left 와 right 가 정렬이 되어 있지 않은 상황에서 개수를 파악하는 방법은 right의 각각의 원소에 대해서 left구간을 전부 탐색을 해야하므로, Partitioning 을 하고 다시 카운팅을 하기 전에 각각의 left, right 부분집합들을 정렬해준다면 투 포인터 방식으로 인덱스를 옮겨가며 N시간만에 개수를 파악할 수 있다.
left, right 부분집합들이 정렬되어 있는 상태에서 카운팅을 하는 방법을 살펴보자.
초기 상태는 다음과 같다.
현재, i < j 이고 arr[i] 보다 arr[j] 가 더 작은 상태이므로 현재 arr[j]보다 크고 i < j 를 만족하는 arr[i] 가 2개 존재하므로 이것을 카운팅 변수에 더하고, 이 후 정렬된 새로운 집합(오름차순)에 arr[j]를 넣어준다. 그렇다면 다음과 같은 상태가 될 것이다.
이 후 동일하게 arr[i], arr[j]를 비교한다. 이 상황에서 arr[i] 가 arr[j] 보다 작으므로 더 작은 값을 "정렬된 새로운 집합"에 넣어주고 다음으로 넘어간다.
동일한 과정을 반복한다면, i 또는 j 가 범위를 벗어날 때 범위를 벗어나지 않는 쪽 인덱스 부터 끝까지 정렬된 새로운 집합에 넣어주는 것으로 부분 정렬과 동시에 카운팅을 수행할 수 있다.
전체적인 코드는 Merge Sort를 수행하는 과정에서 카운팅을 하는 부분만 추가하면 되는 구조이다.
총 시간복잡도는 ${O(NlogN)}$이다.
소스 코드
#include <bits/stdc++.h>
using namespace std;
vector<int> arr;
long long answer = 0;
void counting(int l, int m, int r){
int i = l, j = m+1;
int k = 0;
vector<int> tmp(r-l+1);
// 시간복잡도를 줄이기 위해
while(i <= m && j <= r ){
if( arr[i] > arr[j] ) {
answer += ( m - i + 1 );
tmp[k++] = arr[j];
j += 1;
}
else{
tmp[k++] = arr[i];
i += 1;
}
}
if( m < i ){
while( j <= r )
tmp[k++] = arr[j++];
}
else{
while( i <= m )
tmp[k++] = arr[i++];
}
for(int i=l, k=0; i<=r; i++){
arr[i] = tmp[k++];
}
}
void partition(int l, int r){
if( l >= r )
return;
int m = (l+r)/2;
partition(l, m);
partition(m+1, r);
counting(l, m, r);
}
// 부분 정렬 까지 수행해야하는 이유 ?? :
// 구간에서 개수를 카운팅하기 위한 시간복잡도 줄이기 위함, 정렬 x시 최대 N^2
int main(void){
ios_base::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int N ;
cin >> N;
arr.resize(N);
for(int i=0; i<N; i++)
cin >> arr[i];
partition(0, N-1);
cout << answer ;
return 0;
}
'자료구조 + 알고리즘 > [BOJ]' 카테고리의 다른 글
[BOJ] 2151번 - 거울 설치 (0) | 2021.07.12 |
---|---|
[BOJ] 2342 - Dance Dance Revolution (0) | 2021.06.03 |
[BOJ] 1208번 - 부분수열의 합 2 (0) | 2021.04.28 |
[BOJ] 1202번 - 보석 도둑 (0) | 2021.04.27 |
[BOJ] 1766번 - 문제집 (0) | 2021.04.26 |