BOJ 14458 - 소가 길을 건너간 이유 10

image.png

Inversion Counting을 계속 원소들을 교체해가면서 세주는 문제이다.

여기서 처음 배열의 Inversion Counting을 세준다음에, 생각해보자.

제일 뒤의 원소를 제일 앞으로 보내는 연산은 다음과 같이 개수에 영향을 미친다.

$i$가 $to[i]$ 로 가야할 때, $n-1-to[i]$ 개 만큼 개수가 줄어든다.

왜냐면 $i$가 현재 가장 제일 마지막 원소이기 때문에 그것과 교차하는 것은 $n-1-to[i]$ 개의 $to[i]$ 오른쪽에 있는 원소들의 개수이기 때문이다.

또, $to[i]$ 만큼 교차하는 것의 개수가 늘어난다.

가장 앞으로 가면 그것과 교차하는 것의 개수는 $to[i]$개 가 증가하기 때문이다.

그러므로 이 연산을 쭉 해주면 된다.

주의할건, 처음 배열이 $A,B$ 가 주어졌을 때, $A$에서도 정답을 구해보고 $B$에서도 정답을 구해봐야 한다는 것이다.

struct fenwick {  
   vi tree;  
   int n;  
   fenwick(int n) : n(n), tree(vi(n + 1)) {}  
  
   void update(int i, int v) {  
      i++;  
      while (i <= n) {  
         tree[i] += v;  
         i += i & -i;  
      }  
   }  
   int sum(int i) {  
      i++;  
      int ret = 0;  
      while (i) {  
         ret += tree[i];  
         i -= i & -i;  
      }  
      return ret;  
   }  
};  
  
void solve() {  
   int n;  
   cin >> n;  
   vi a(n), c(n);  
   fv(a);  
   fv(c);  
   for (int &i: a) i--;  
   for (int &i: c) i--;  
   int A = 2e15;  
   for (int it = 0; it < 2; it++) {  
      auto b = c;  
      vi idx(n), to(n);  
      for (int i = 0; i < n; i++) idx[a[i]] = i;  
      for (int i = 0; i < n; i++) b[i] = idx[b[i]];  
      for (int i = 0; i < n; i++) to[b[i]] = i;  
  
      fenwick fenw(n);  
      ll inv = 0;  
      for (int i = n - 1; i >= 0; i--) {  
         inv += fenw.sum(to[i]);  
         fenw.update(to[i], 1);  
      }  
      ll ans = inv;  
      for (int i = n - 1; i >= 0; i--) {  
         inv += b[i] * 2ll - n + 1;  
         ans = min(ans, inv);  
      }  
      A = min(A, ans);  
      swap(a, c);  
   }  
   cout << A;  
}

Tags:

Categories:

Updated:

Comments