2/1
CEOIの問題は良いのが多いですね。
PKU 3652
やるだけ。
PKU 3653
だいくすとら。
PKU 3654
やるだけ。
PKU 2452
solve(a, b) を S[a..b] におけるこの問題の解を求める関数とすると、solve(a, b)は以下のような実装になる。
0. b >= a なら -1 を返す
1. S[a..b] 中の最大値 S[maxi] を求める
2. S[a..b] 中の最小値 S[mini] を求める
3. max{ maxi-mini, solve(a, mini-1), solve(maxi+1, b) } を返す
ここで最大値、最小値を効率よく求めるためにRMQを使ってやるとよい。
PKU 1934
LCSを求めるDPに+αしたようなもの。
DPの表の上で A[i] == B[j] となるような (i, j) の位置を頂点として、 dp[i][j] + 1 == dp[i'][j'] かつ i < i' かつ j < j' の場合にのみ (i, j) → (i', j') の有向辺が存在するようなグラフを考える。
そのグラフ上で dp[x][y] が A, B のLCSと等しくなるような頂点 (x, y) までの経路を辿るとよい。
PKU 2274
まず全体の追い越し回数を求める。
V[i] > V[j] なら i はいつか必ず j を追い越すということに注目すると、全体の追い越し回数は V[1..N] をバブルソートした時の交換回数となる。これはマージソートっぽい感じで求めてもいいし、0 < V[x] < 100 だからBinary Indexed Treeを使っても良い。結局 O(N log N)。
次に最初の10000回の追い越しを求める。
基本的な考え方としては追い越しのイベントをヒープに入れて、その追い越しが起きる時間が早い方から取り出して行く方法。i が j を追い越す(i < j)とすると、それ以前に i < x < j なる x を i は追い越しているはずである。なのでとりあえず i が i+1 を追い越すようなイベントだけを最初はヒープに入れておく。
i が j を追い越すイベントがヒープから取り出されたとき、まずそれを表示する。そして今度は i が i+1 を追い越すイベント、 j-1 が j を追い越すイベントをそれぞれヒープに入れる。これでO(N + P log N)。ただしP = min{10000, 全体の追い越し回数}。
PKU 1920
まずどこに移せばよいかは、最初に円盤N(いちばんでかいやつ)があるところで決定。
count(n, dst) を 1..n の円盤を棒dstに移すのに必要な移動回数を表すものとする。これは次のように実装できる。
0. n < 1なら0を返す。
1. nが既にdstにあるなら count(n-1, dst) を返す。
2. nがある棒でもなく、dstでもない棒を作業棒とする。
3. count(n-1, 作業棒) + 2n-1 を返す。
最後にcount(n-1, 作業棒) + 2n-1 を返せばよいのは次の理由による。
まず、1..n-1 の円盤を作業棒に移すと n の円盤は1回の移動で dst へ移すことができる。またこのとき、作業棒には 1..n-1 の円盤が全てあるので、これを dst へ移すのに必要な移動回数は 2n-1-1 回となる。