問題にチャレンジして、ユーザー同士で解答を教え合ったり、コードを公開してみよう!
マージソート (昇順) は、データ列を二分し、それぞれをマージソートした後それらを「マージ (統合) 」する
ことを繰り返すソートアルゴリズムです。マージソートは、問題を小さな問題に分割して解くことを繰り返すことによって元の問題の答えを得る手法である「分割統治法」に基づいたアルゴリズムです。
マージソート (昇順) は以下のようなアルゴリズムです。データ列を二分してマージソートを行う merge_sort
と、昇順にソートされた2つの部分データ列をマージする merge
から成ります。
// アルゴリズムが正しく実装されていることを確認するために導入するカウンタ変数、ソート処理には関係がないことに注意
count <- 0
/**
部分データ列 A[left] ~ A[mid-1], A[mid] ~ A[right-1] はそれぞれ整列済み
2つの部分データ列をマージし、A[left] ~ A[right-1] を整列済みにする
*/
merge(A : 配列, left : 整数, mid : 整数, right : 整数)
// 2つの部分データ列のサイズ
nl <- mid-left
nr <- right-mid
// 部分データ列をコピー
for i = 0 to nl-1
L[i] <- A[left+i]
for i = 0 to nr-1
R[i] <- A[mid+i]
// 番兵
L[nl] <- INF
R[nr] <- INF
// 2つの部分データ列をマージして A[left] ~ A[right-1] に書き込む
lindex <- 0
rindex <- 0
for i = left to right-1
if L[lindex] < R[rindex] then
A[i] <- L[lindex]
lindex++
else
A[i] <- R[rindex]
rindex++
count++
/**
A[left] ~ A[right-1] をマージソートする
配列 A をマージソートするには merge_sort(A, 0, n) を呼び出す
*/
merge_sort(A : 配列, left : 整数, right : 整数)
if left+1 < right
mid = (left + right) / 2
merge_sort(A, left, mid)
merge_sort(A, mid, right)
merge(A, left, mid, right)
lindex
や rindex
がそれぞれ nl
, nr
未満であるかどうかを確かめながら複雑な条件分岐の処理を書く必要が出てきます。今回は、入力の最大値より大きい数 INF
を2つのデータ列の末尾に配置することで、番兵を実現しています。merge_sort
ではデータ列を2つに分割していますが、この分割は入力されるデータ列のサイズ n に対して約 log n 段行われます (上図参照) 。そして、各段のマージに合計 O(n) かかるため、マージソート全体の計算量は O(n log n) です。count
の値を出力してください。
n
A_1 A_2 ... A_n
2行出力してください。
1行目に、ソート後の数列 A' の各要素を半角スペース区切りで出力してください。
2行目に、count
を出力してください。
また、末尾に改行を入れ、余計な文字、空行を含んではいけません。
A'_1 A'_2 ... A'_n
count
すべてのテストケースにおいて、以下の条件をみたします。
・ 1 ≦ n ≦ 500,000
・ -1,000,000,000 ≦ A_i ≦ 1,000,000,000 (1 ≦ i ≦ n)
10
7 6 10 2 5 4 8 3 9 1
1 2 3 4 5 6 7 8 9 10
19