https://community.topcoder.com/stat?c=problem_statement&pm=15960
前提知識
解説
なるべく少ない個数の要素を修正して、辞書順最小の非減少列を作成するという問題。
構築の部分は後で考えるとして、修正すべき要素数を考える。
修正すべき個数の最小化ではなく、修正しなくていい個数の最大化と言い換えてみよう。
すると、これはLISと同じ問題となる。
LISのよくある回答である、セグメントツリー解法などで解いてもよいが、今回はO(N2)が許されるので、
自分より前で最も長いLISを愚直に探そう。
この時に以下の配列を構築していく。
top[i] := 最後がA[i]であるLISの最大長
pre[i] := 最後がA[i]であるLISの1つ前の要素とでき、そのうち最も近いもの
LISとして固定するものが決まったら、その間をなるべく小さい数で埋めていくのだが、LISは何通りもある。
固定するLISはなるべく後ろにして、前に編集可能な部分を残してなるべく小さい数で埋めたい。
ここで配列preを使用する。
LISの長さが最長のものを固定するLISの末尾として、そこからpreを使ってさかのぼっていくと固定に最適なLISが得られる。
あとは、配列chkを使って、固定する要素に印をつけておいて、先頭から置ける最も小さい数で埋めていけばいい。
int top[2010], pre[2010], chk[2010]; struct ArraySorting { vector <int> arraySort(vector <int> A) { int n = A.size(); rep(i, 0, n) { top[i] = 0; pre[i] = -1; rep(j, 0, i) if (A[j] <= A[i]) { if (top[i] <= top[j]) { top[i] = top[j]; pre[i] = j; } } top[i]++; } int ma = 0; rep(i, 0, n) chmax(ma, top[i]); int ma_i = 0; rep(i, 0, n) if (ma == top[i]) ma_i = i; chk[ma_i] = 1; while (0 <= ma_i) { ma_i = pre[ma_i]; if(0 <= ma_i) chk[ma_i] = 1; } int x = 1; rep(i, 0, n) { if (chk[i]) x = A[i]; A[i] = x; } return A; } };