Softeer

[C++] 소프티어 [인증평가 4차 기출] 통근버스 출발 순서 검증하기

MINU.SHINNNN 2023. 1. 18. 16:06

https://softeer.ai/practice/info.do?idx=1&eid=654 

 

Softeer

문제에서 주어진 조건을 만족하는 서로 다른 (i, j, k) 순서쌍의 개수를 출력한다. 첫 번째 위치에는 2번 버스, 두 번째 위치에는 3번 버스, 그리고 세 번째 위치에는 1번 버스가 기다

softeer.ai

풀이

정렬 불가능한 조합이 몇 개나 있는지 세는 문제이다.

Brute-Force로 모든 조합에 대해 검사할 경우 O(N^3)이기 때문에 5000^3 = 125,000,000,000 (1250초?) 이므로 다른 알고리즘이 필요하다.

Prefix Sum, 구간 합 개념을 사용한다면 O(N^2) 25,000,000 으로 1초 안에 계산을 마칠 수 있다.

1. 문제 조건에 의해 i < j < k 에 대해 a_k < a_i < a_j 의 조합을 찾아야 한다.

2. 이 때, 주어진 배열에서 a_i 와 a_j 를 결정했을 때 이미 정답(가능한 a_k의 수)을 알고 있으면 된다.

3. 이를 위해 a_i를 가능한 모든 수(1~N) 에 대해 돌려보면서 j 보다 오른쪽에 있는 수(a_k 후보)에 대해 a_k < a_i를 만족할 경우 카운트 해주면 된다.

4.  if ( arr[j] < num ) 은 a_k < a_i 를 확인한 것이고, 참일 경우 arr_1[i][j-1] 에 업데이트 한다. ( j는 j-1 보다 오른쪽에 있는 숫자다) 

5. 마지막으로 이중 for loop 로 가능한 모든 a_i < a_j 에 대해 arr_1[ arr[ i ] ][ j ] 를 통해 답을 업데이트 하면 된다. 

#include<iostream>
#include<vector>

using namespace std;

long long int answer = 0;

int main(int argc, char** argv)
{
	int n;
	int val;
	vector<int> arr;
	
	cin >> n;

	vector<vector<unsigned int>> arr_1(n+1, vector<unsigned int>(n,0));
	
	for (int i = 0; i < n; i++) {
		cin >> val;
		arr.push_back(val);
	}

	// j보다 오른쪽에 있는 수 중에, a_k < a_i(임의의 자연수) 만족하는 개수 찾기
	for (int num=1; num<=n; num++) {
		for (int j = n-1; j>=1; j--) {
			if (arr[j] < num) {
				arr_1[num][j-1] = arr_1[num][j] + 1;
			}
			else {
				arr_1[num][j-1] = arr_1[num][j];
			}
		}
	}

	for (int i=0; i<n-2; i++) {
		for (int j=i+1; j<n-1; j++) {
			if (arr[i] < arr[j]) {
				answer += arr_1[arr[i]][j];
			}
		}
	}
	cout << answer << endl;
	return 0;
}