D - Permutation Ordering

2 secs 1024 MB
uni_kakurenbo's icon uni_kakurenbo

概要

いくつかの方針が存在しそうです.

問題原案:Syntax_Error_

解説

22 通りの解法を紹介します:

  • ソートの過程をシミュレーションする.
  • i,Pii, P_i 間に辺を張った NN 頂点のグラフにおける連結成分の個数を考える.

シミュレーションをする解法

操作によって,好きな数を好きな位置に移動することができます.
既にソートされている部分を変更せずに,残りの部分を順に一致させていくことができます.

たとえば先頭から順に一致させていくことで最適な操作手順の一例が得られます.

「整数 xx は列 PP の何番目か?」という情報が分かればいいので,最初に Pi=xP_i = x となるような ii1xN1 \leq x \leq N なるすべての整数について求めておいうたうえで,操作のシミュレーション時に PP と同時に更新していくとよいでしょう.(詳しくは実装例も参照してください.)

連結成分の個数を利用する解法

頂点 1,2,,N1, 2, \ldots, N をもつ NN 頂点のグラフ GG を考え,頂点 i(1iN)i \scriptsize \; (1 \leq i \leq N) と 頂点 PiP_i とを結ぶ辺を張ります.

このとき,((連結成分の大きさ)1) - 1GG のすべての連結成分について足し合わせた値,すなわち N(GN - ( G の連結成分の個数)) が答えに一致します.

これを証明します:

  • 各辺を iPii \to P_i の有向辺とする.
  • すべての頂点は,入辺と出辺を 11 本ずつ持つから,GG はサイクルのみからなるグラフになる.
  • また,頂点 ii と 頂点 PiP_i とは同一の連結成分(サイクル)に属するから,連結成分ごとにソートすればよい.(これが最適)
    • 他の連結成分に属する頂点と交換する必要はないことを考えるとわかる.
  • KK 頂点のサイクルをソートするには K1K - 1 回の操作が最適で,この総和が答え.
    • K=1K = 1 (自己ループ) のとき :
      • i=Pii = P_i となっている場合.ソートされているので 0(=K1)0 \,(= K - 1) 回.
    • K>1K > 1 のとき:
      • i=Pii = P_i なる ii は存在しない.
      • サイクルに属する頂点のうち一つを目的の位置に移動させると,大きさ 1,K11, K-122 つにサイクルに分離する.
      • K1K-1 回の分離で,大きさ 11 のサイクル KK 個になる.

解説:uni_kakurenbo

実装例

C++
C++