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

 

5012번: 불만 정렬

문제 정렬 알고리즘의 상한(upper bound)은 n2이다. 이 사실은 쉽게 증명할 수 있다. 올바른 순서가 아닌 임의의 두 원소(ai > aj, i < j)를 선택하고, 그 위치를 서로 바꿔준다. 이렇게 올바른 순서가 아닌 것을 도치(inversion)라고 하며, 도치의 개수는 최대 n(n-1)/2개이다.  현주는 사회에 대한 불만이 많은 아이이다. 그는 항상 정렬을 할 때, 두 원소를 선택하는 것에도 큰 불만을 가지고 있다. 현주는 ai > aj >

www.acmicpc.net


문제해설

"펜윅 트리"를 사용하여 풀었습니다.

이 문제는 밑의 문제와 굉장히 유사한 문제라고 할 수 있습니다.

2019/10/06 - [알고리즘/BOJ] - [백준BOJ] 3006 터보소트

 

[백준BOJ] 3006 터보소트

https://www.acmicpc.net/problem/3006 3006번: 터보소트 문제 명우가 소트 알고리즘을 하나 발명했다. 이 알고리즘의 이름은 터보소트이다. 터보소트는 1부터 N까지 총 N개의 수가 섞여있을 때만 사용할 수 있으..

polohee81.tistory.com

i < j < k 이면서 Ai > Aj > Ak

인 경우의 수를 찾기 위해서는

j를 기준으로 왼쪽, 오른쪽을 탐색하면 됩니다.

 

< 변수 >

#define MAX_N 100000
int tree_left[MAX_N + 1];
int tree_right[MAX_N + 1];
vector<int> l, r;

 

case1 : 자신 기준 왼쪽에 있으면서 큰 값의 수

case2 : 자신 기준 오른쪽에 있으면서 작은 값의 수

< case1 >

int left =  query(tree_left, MAX_N) - query(tree_left, data_left);

위의 코드처럼 구간합으로 자신보다 왼쪽에 있으면서 큰 값들의 갯수를 구할 수 있습니다.

 

< case2 >

int right =  query(tree_right,  data_right-1);

위의 코드처럼 구간합으로 자신보다 오른쪽에 있으면서 작은 값들의 갯수를 구할 수 있습니다. 


전체코드

#include <iostream>
#include <vector>
#include <stack>
#include <queue>
#include <algorithm>
#include <cmath>
#include <string>
using namespace std;
vector<int> vec;
#define MAX_N 100000
int tree_left[MAX_N + 1];
int tree_right[MAX_N + 1];
vector<int> l, r;

void update(int tree[],int target, int value) {
     while (target <= MAX_N) {
          tree[target] += value;
          target += (target & -target);
     }
}

int query(int tree[],int target) {
     int ret = 0;
     while (target >= 1) {
          ret += tree[target];
          target -= (target &-target);
     }
     return ret;
}

int main() {
     ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
     int N;
     cin >> N;
     for (int i = 1; i <= N; i++) {
          int data; cin >> data;
          vec.push_back(data);
     }

     long long ans = 0;
     for (int i = 0, j = vec.size()-1; i < vec.size(); i++, j--) {
          int data_left = vec[i]; 
          int data_right = vec[j];

          int right =  query(tree_right,  data_right-1);
          int left =  query(tree_left, MAX_N) - query(tree_left, data_left);
          l.push_back(left); r.push_back(right);

          update(tree_right, data_right, 1);
          update(tree_left, data_left, 1);

     }
     for (int i = 0, j = r.size()-1; i < l.size(); i++,j--) {
          ans += ((long long)l[i] * r[j]);
     }
     cout << ans << "\n";
}

 

 

'알고리즘 > [C++]BOJ' 카테고리의 다른 글

[백준BOJ] 10774 저지  (0) 2019.10.07
[백준BOJ] 3006 터보소트  (0) 2019.10.06
[백준BOJ] 1280 나무 심기  (0) 2019.10.06

+ Recent posts