47
「みんなのプロコン」 本選 解説 maroonrk, semiexp

「みんなのプロコン」 本選解説•貪欲法で解ける •「実力差がX 以下になる参加者のペアのうち,最 も実力の値が大きいペアから順に取っていく」を繰

  • Upload
    others

  • View
    2

  • Download
    0

Embed Size (px)

Citation preview

Page 1: 「みんなのプロコン」 本選解説•貪欲法で解ける •「実力差がX 以下になる参加者のペアのうち,最 も実力の値が大きいペアから順に取っていく」を繰

「みんなのプロコン」本選解説

maroonrk, semiexp

Page 2: 「みんなのプロコン」 本選解説•貪欲法で解ける •「実力差がX 以下になる参加者のペアのうち,最 も実力の値が大きいペアから順に取っていく」を繰

A 問題:YahooYahooYahoosemiexp

Page 3: 「みんなのプロコン」 本選解説•貪欲法で解ける •「実力差がX 以下になる参加者のペアのうち,最 も実力の値が大きいペアから順に取っていく」を繰

問題概要

•文字列 S に対して次の操作ができる• 任意の 1 文字削除• 任意の位置に 1 文字挿入• 任意の 1 文字変更

• S を “Yahoo” の繰り返しにするのにかかる操作回数の最小値は?

Page 4: 「みんなのプロコン」 本選解説•貪欲法で解ける •「実力差がX 以下になる参加者のペアのうち,最 も実力の値が大きいペアから順に取っていく」を繰

文字列の編集距離

• 「“Yahoo” の繰り返し」のほうが固定文字列だったら有名問題(文字列の編集距離)

• この場合は DP で解ける

• dp[i][j]: S[1..i], T[1..j] の間の編集距離

Page 5: 「みんなのプロコン」 本選解説•貪欲法で解ける •「実力差がX 以下になる参加者のペアのうち,最 も実力の値が大きいペアから順に取っていく」を繰

この問題の解法

• dp[i][j]: S[1..i] を YahooYahoo…YahooYah (最後はYahoo の先頭 j 文字)にするのにかかる最小操作数として DP

•遷移は編集距離の場合とほとんど同じ

Page 6: 「みんなのプロコン」 本選解説•貪欲法で解ける •「実力差がX 以下になる参加者のペアのうち,最 も実力の値が大きいペアから順に取っていく」を繰

注意

• DP 遷移が循環する• dp[i][0] -> dp[i][1] -> dp[i][2] -> dp[i][3] -> dp[i][4] ->

dp[i][0] -> …•適当に 1 周だけすると境界でおかしいことになりうる

• 例えば 4 -> 0 -> 1 -> 2 -> 3 -> 4 みたいな遷移だけをやると,”yahyahoo” でWA になるはず

• 2 周すれば OK• 最適なパスを考えると,1 周以上は絶対にしない• 2 周しておけば,必要などんなパスも網羅できる

Page 7: 「みんなのプロコン」 本選解説•貪欲法で解ける •「実力差がX 以下になる参加者のペアのうち,最 も実力の値が大きいペアから順に取っていく」を繰

B: チーム決めsemiexp

Page 8: 「みんなのプロコン」 本選解説•貪欲法で解ける •「実力差がX 以下になる参加者のペアのうち,最 も実力の値が大きいペアから順に取っていく」を繰

問題概要

• チーム高橋には N 人の候補者がいて,K 人をコンテストに参加させたい

• チーム青木にはM 人の候補者がいて,K 人をコンテストに参加させたい

•各参加者には「実力」が定まっている• 「両チーム内で i番目に強い参加者の実力差」の

max を最小化したい

Page 9: 「みんなのプロコン」 本選解説•貪欲法で解ける •「実力差がX 以下になる参加者のペアのうち,最 も実力の値が大きいペアから順に取っていく」を繰

解法の方針

•最大値最小化•二分探索をしたくなる• チーム間の実力差を X 以下にできるかを判定する問題を考える

Page 10: 「みんなのプロコン」 本選解説•貪欲法で解ける •「実力差がX 以下になる参加者のペアのうち,最 も実力の値が大きいペアから順に取っていく」を繰

判定問題

•貪欲法で解ける• 「実力差が X 以下になる参加者のペアのうち,最も実力の値が大きいペアから順に取っていく」を繰り返して,K ペア作れれば OK

Page 11: 「みんなのプロコン」 本選解説•貪欲法で解ける •「実力差がX 以下になる参加者のペアのうち,最 も実力の値が大きいペアから順に取っていく」を繰

正当性の証明

• まず,そのようなペアは自然に定まることに注意する• チーム高橋 / 青木の中で,「相手チームからペアの相手を選べる人」のうち実力が最大の人,をそれぞれ選んでくると,その 2 人同士はペアになれる

• このペアを使わない解があったら,適当なペアを外して実力最大ペアに置き換えてもよいから,この実力最大ペアは使うとしてよい

•次のペアは,残った人の中から実力最大ペアを選べばよいことが同様にわかる

• …

Page 12: 「みんなのプロコン」 本選解説•貪欲法で解ける •「実力差がX 以下になる参加者のペアのうち,最 も実力の値が大きいペアから順に取っていく」を繰

アルゴリズム

• チームごとに,候補者を実力でソート• チーム高橋の中で,実力が大きいほうから順に,「その人の実力を X として,X-K 以上 X+K 以下の実力を持つ人が,チーム青木(の中でまだペアにしてない人たち)の中にいるか」を二分探索で判定

• そのような人がいれば,その中で最も実力が大きい人とペアにする

• さもなくば,その人はペアにせず,次の人を見る•最終的に K ペアできていれば OK

Page 13: 「みんなのプロコン」 本選解説•貪欲法で解ける •「実力差がX 以下になる参加者のペアのうち,最 も実力の値が大きいペアから順に取っていく」を繰

アルゴリズム

• このアルゴリズムは O(N log N) で動作• 事前にソートしてあれば,尺取法を用いて O(N)でやることもできる

•二分探索をするので,実力の最大値をM としてO(N log N log M)

Page 14: 「みんなのプロコン」 本選解説•貪欲法で解ける •「実力差がX 以下になる参加者のペアのうち,最 も実力の値が大きいペアから順に取っていく」を繰

C: 倍数クエリsemiexp

Page 15: 「みんなのプロコン」 本選解説•貪欲法で解ける •「実力差がX 以下になる参加者のペアのうち,最 も実力の値が大きいペアから順に取っていく」を繰

問題概要

•数列 𝐴1, 𝐴2, … , 𝐴𝑁と,定数𝑀が与えられる• 𝐴𝐿𝑖, 𝐴𝐿𝑖+1, … , 𝐴𝑅𝑖 に一律に 𝐷𝑖 を加え,その後この中に含まれる𝑀の倍数の個数を求めるクエリを 𝑄回処理する

Page 16: 「みんなのプロコン」 本選解説•貪欲法で解ける •「実力差がX 以下になる参加者のペアのうち,最 も実力の値が大きいペアから順に取っていく」を繰

解法

•数列上である区間にある値について,mod𝑀 での個数を持っておくことを考える

• 「この区間全体に 𝐷 を足す」「この区間全体の𝑀の倍数の個数を求める」のは,区間全体に足された値を別に覚えておけば 𝑂(1)

• この区間に対して,中途半端に操作をするときは,操作対象の位置全部をいちいち調べないといけない

Page 17: 「みんなのプロコン」 本選解説•貪欲法で解ける •「実力差がX 以下になる参加者のペアのうち,最 も実力の値が大きいペアから順に取っていく」を繰

解法

•長さ 𝑁ごとに区間を区切って前ページに述べたことをやる(平方分割)

• クエリ操作は,• 区間全体に亘る操作:𝑂 𝑁

(区間が 𝑁個,各区間で 𝑂 1 の操作)• 区間に対して中途半端な操作:𝑂 𝑁

(区間長が 𝑁で,関係する区間は高々 2 個)

• 𝑂(𝑄 𝑁)となるので間に合う

Page 18: 「みんなのプロコン」 本選解説•貪欲法で解ける •「実力差がX 以下になる参加者のペアのうち,最 も実力の値が大きいペアから順に取っていく」を繰

D: KthLIS解説maroonrk

Page 19: 「みんなのプロコン」 本選解説•貪欲法で解ける •「実力差がX 以下になる参加者のペアのうち,最 も実力の値が大きいペアから順に取っていく」を繰

問題概要

•長さ N の配列 A が与えられる

•辞書順で K 番目の最長増加部分列を出力

Page 20: 「みんなのプロコン」 本選解説•貪欲法で解ける •「実力差がX 以下になる参加者のペアのうち,最 も実力の値が大きいペアから順に取っていく」を繰

考察

• とりあえず、LISの長さを求め、L と置きます

• LISの求め方は、この本選に来ている皆さんならばおそらく知っているはずです

Page 21: 「みんなのプロコン」 本選解説•貪欲法で解ける •「実力差がX 以下になる参加者のペアのうち,最 も実力の値が大きいペアから順に取っていく」を繰

考察

• あらかじめ、A の末尾に番兵として infを付け足したものとします

• こうすると、任意のLISが最後の要素を含むことになるので、あとで便利です

Page 22: 「みんなのプロコン」 本選解説•貪欲法で解ける •「実力差がX 以下になる参加者のペアのうち,最 も実力の値が大きいペアから順に取っていく」を繰

考察

•全ての i(1<=i<=N) について B[i] を以下のように定めますB[i]=A[1:i]の単調増加な部分列であって、最後の要素が A[i] であるものの最長の長さ

• B[i] は、普通にLISを求める途中で出てきます

Page 23: 「みんなのプロコン」 本選解説•貪欲法で解ける •「実力差がX 以下になる参加者のペアのうち,最 も実力の値が大きいペアから順に取っていく」を繰

考察

• ここで、問題を次のように言い換えます

• N 頂点からなるグラフがあり、すべてのi,j(1<=i<j<=N) について、B[i]+1=B[j] ならば i->j の有効辺を張る

• L 頂点を通るパスのうち、A[通る頂点番号] を並べたものが辞書順で K 番目のものを求める

Page 24: 「みんなのプロコン」 本選解説•貪欲法で解ける •「実力差がX 以下になる参加者のペアのうち,最 も実力の値が大きいペアから順に取っていく」を繰

考察

• このままでは、有向グラフ上の異なる二つのパスで、 A[通る頂点番号] を並べたものが重複することがあります

• これはいったいどのような状況でしょうか

Page 25: 「みんなのプロコン」 本選解説•貪欲法で解ける •「実力差がX 以下になる参加者のペアのうち,最 も実力の値が大きいペアから順に取っていく」を繰

考察

• このような形があると、重複が起きそうです• ではどうすれば防げるでしょうか?

A[i]=A[j]

i

A[j]=A[i]

j

A[p]>A[i]

pB[i]=B[j]

B[i]+1=B[p]

Page 26: 「みんなのプロコン」 本選解説•貪欲法で解ける •「実力差がX 以下になる参加者のペアのうち,最 も実力の値が大きいペアから順に取っていく」を繰

考察

• この辺を消せばよさそうです→実際うまくいきます

A[i]=A[j]

i

A[j]=A[i]

j

A[p]>A[i]

pB[i]=B[j]

B[i]+1=B[p]

Page 27: 「みんなのプロコン」 本選解説•貪欲法で解ける •「実力差がX 以下になる参加者のペアのうち,最 も実力の値が大きいペアから順に取っていく」を繰

考察

• より正確に書けば、i,j,p (1<=i<j<p<=N) であって、A[i]=A[j],B[i]=B[j],B[i]+1=B[p]を満たすものがある時、i->p の辺を消します

•消すことによって、数え漏れが生じる(存在するはずだったパスが消えて、重複しないものも消してしまう)ことが起きないことは、すぐに確認できます

Page 28: 「みんなのプロコン」 本選解説•貪欲法で解ける •「実力差がX 以下になる参加者のペアのうち,最 も実力の値が大きいペアから順に取っていく」を繰

考察

• また、先ほどのような辺を全て消すことで、重複の起きるパスがなくなることもわかります

• よって、先ほどのような辺のない有向グラフを構築し、長さ L のパスであって、A[通る頂点番号] を並べたものが辞書順で K 番目であるものを素直に求めればよいとわかります

Page 29: 「みんなのプロコン」 本選解説•貪欲法で解ける •「実力差がX 以下になる参加者のペアのうち,最 も実力の値が大きいペアから順に取っていく」を繰

考察

•制約的にグラフの構築がそもそも愚直に行えませんが、それについては後回しにします

Page 30: 「みんなのプロコン」 本選解説•貪欲法で解ける •「実力差がX 以下になる参加者のペアのうち,最 も実力の値が大きいペアから順に取っていく」を繰

考察

•辞書順で K 番目のものを求めるまえに、そもそも全部で何通りのパスがあるのかを求めてみます

• これは DP で計算できますDP[i]= 頂点 iを出発し、B[j]=L を満たす全ての jにたどり着く場合の数と定義します

Page 31: 「みんなのプロコン」 本選解説•貪欲法で解ける •「実力差がX 以下になる参加者のペアのうち,最 も実力の値が大きいペアから順に取っていく」を繰

考察

•初期値として、DP[N]=1 とします(A の末尾の要素は infであり、これは任意のLISに含まれるため)

• あとは、B[i] の大きいものから順に DP[i] を更新していきます

•遷移は、iから出る辺の行き先を v1,v2,v3… としたとき、DP[i]=DP[v1]+DP[v2]+DP[v3]+… となります

Page 32: 「みんなのプロコン」 本選解説•貪欲法で解ける •「実力差がX 以下になる参加者のペアのうち,最 も実力の値が大きいペアから順に取っていく」を繰

考察

• この情報があれば、辞書順 K 番目のものを復元するのは容易です

• いま、最初の X 個が確定しているならば、B[i]=X+1 となるすべての iを、A[i] の小さい方から試します

• ある頂点を移動先として選んだ時に、そこから何通りのパスがあるかはDPで求めてあるので、辞書順 K 番目のものが含まれているものを見つけたらそこに移動します

Page 33: 「みんなのプロコン」 本選解説•貪欲法で解ける •「実力差がX 以下になる参加者のペアのうち,最 も実力の値が大きいペアから順に取っていく」を繰

考察

•今までのことをそのままやるとグラフの変数がO(N^2) になって大変なので、頑張って削ります

• グラフの辺を使うのは、DPを求める時と、辞書順 K 番目のものを復元する時です

Page 34: 「みんなのプロコン」 本選解説•貪欲法で解ける •「実力差がX 以下になる参加者のペアのうち,最 も実力の値が大きいペアから順に取っていく」を繰

考察

•頂点 iから出る辺の行き先となる頂点の集合は、B[j]=B[i]+1,Si<=j<=Ti(Si,Tiは iに応じて決まる数)を満たす j すべてであることがわかります

• すると、B[i] の値ごとに頂点をグループ分けし、グループごとに DP[i] の累積和を求めておけば、陽にグラフを持たずに、高速にDPの更新が行えるとわかります

Page 35: 「みんなのプロコン」 本選解説•貪欲法で解ける •「実力差がX 以下になる参加者のペアのうち,最 も実力の値が大きいペアから順に取っていく」を繰

考察

• また、復元の時は、それぞれの頂点について、その頂点に移動するかどうかを検討する回数が 1 回しかないので、グラフの辺をたどる操作は全体でO(N) 回しかありません

• よって、グラフを陽に持っていなくても、行いたい操作はすべて行えることがわかりました

Page 36: 「みんなのプロコン」 本選解説•貪欲法で解ける •「実力差がX 以下になる参加者のペアのうち,最 も実力の値が大きいペアから順に取っていく」を繰

まとめ

• LISを求めるのに O(NlogN)

•各 iについて、Si,Tiを求めるのは、二分探索を使えば O(logN) ででき、全部で O(NlogN)

• DPの更新、LISの復元はどちらも O(N)

• よって全体で O(NlogN) でこの問題は解けました

Page 37: 「みんなのプロコン」 本選解説•貪欲法で解ける •「実力差がX 以下になる参加者のペアのうち,最 も実力の値が大きいペアから順に取っていく」を繰

E: 瞬間移動装置semiexp

Page 38: 「みんなのプロコン」 本選解説•貪欲法で解ける •「実力差がX 以下になる参加者のペアのうち,最 も実力の値が大きいペアから順に取っていく」を繰

問題概要

• N 個の都市があり,各都市間には瞬間移動装置がある

• しかし,M 個の瞬間移動装置は壊れていて使えない

• 「都市 𝑐𝑖から 𝑑𝑖 まで移動するのに,最小で瞬間移動装置を何回使えばいいか」というクエリに Q 回答える

Page 39: 「みんなのプロコン」 本選解説•貪欲法で解ける •「実力差がX 以下になる参加者のペアのうち,最 も実力の値が大きいペアから順に取っていく」を繰

問題概要

•要は,グラフが与えられるので,その補グラフ上で最短経路長クエリを解け

•元のグラフを 𝐺,補グラフを ҧ𝐺 で表します• s から t までの最短経路長を考える

Page 40: 「みんなのプロコン」 本選解説•貪欲法で解ける •「実力差がX 以下になる参加者のペアのうち,最 も実力の値が大きいペアから順に取っていく」を繰

N が大きい場合?

• N が大きければ, ҧ𝐺はかなり密になりそう• 𝐺 で辺がなければ 1 で行ける•密なので,辺があったとしてもだいたい 2 で行けそう

Page 41: 「みんなのプロコン」 本選解説•貪欲法で解ける •「実力差がX 以下になる参加者のペアのうち,最 も実力の値が大きいペアから順に取っていく」を繰

1 か 2 で行ける場合

• ҧ𝐺 で s, t のどちらともつながっている頂点が存在すれば,高々 2 で行ける

• s の次数,t の次数がいずれも N/2 より大きければ,どちらともつながっている頂点が存在する

Page 42: 「みんなのプロコン」 本選解説•貪欲法で解ける •「実力差がX 以下になる参加者のペアのうち,最 も実力の値が大きいペアから順に取っていく」を繰

無理な場合

• s, t の ҧ𝐺 での次数が小さい = 𝐺 での次数が大きい場合は,最短路問題を解かないといけない

•普通にやろうとすると, ҧ𝐺の辺数があまりに大きいため困難

•実は O(N+M) でできる

Page 43: 「みんなのプロコン」 本選解説•貪欲法で解ける •「実力差がX 以下になる参加者のペアのうち,最 も実力の値が大きいペアから順に取っていく」を繰

補グラフ最短路

• BFS を行う• BFS の途中で「次訪れる頂点」を知る必要があるが,これは「今見ている頂点の ҧ𝐺での隣接頂点」を列挙するかわりに,「まだ訪れていない頂点」について「今見ている頂点に 𝐺で隣接していないか?」を調べ,隣接していないときはキューに追加

Page 44: 「みんなのプロコン」 本選解説•貪欲法で解ける •「実力差がX 以下になる参加者のペアのうち,最 も実力の値が大きいペアから順に取っていく」を繰

隣接点の列挙

• まだ訪れていない頂点を昇順に vector などで持っておく

•各頂点の隣接リストも昇順にソートしておく• 「まだ訪れていない頂点で,隣接リストに含まれないもの」を列挙するのは,先頭から見ていくことでO(|未訪問頂点| + |隣接頂点|) でできる

• しかも,次の段階の未訪問頂点リストも,ソートされた形で同時に求められる

Page 45: 「みんなのプロコン」 本選解説•貪欲法で解ける •「実力差がX 以下になる参加者のペアのうち,最 も実力の値が大きいペアから順に取っていく」を繰

隣接点の列挙:計算量

•実はこれで BFS を行うと O(N+M) になる

•未訪問頂点数の総和を見積もりたい•一番最初は N-1 個• 2 番目以降は,前回で後回しにされた頂点だけが残る

•各段階では,隣接頂点しか後回しにできない• 「後回し」は合計で高々M 回起きる•全体で O(N+M)

Page 46: 「みんなのプロコン」 本選解説•貪欲法で解ける •「実力差がX 以下になる参加者のペアのうち,最 も実力の値が大きいペアから順に取っていく」を繰

解法

• 𝐺 で次数の小さい (N/2 未満) 頂点同士なら答えはすぐにわかる (1 or 2)

•次数の大きい (N/2 以上) 頂点については,そこから先述の BFS をやっておく

• これでクエリを高速に処理できる

Page 47: 「みんなのプロコン」 本選解説•貪欲法で解ける •「実力差がX 以下になる参加者のペアのうち,最 も実力の値が大きいペアから順に取っていく」を繰

計算量

•次数の大きい頂点は O(M/N) 個• それぞれについて O(N+M) かかる•計算量は O(M^2/N) ???

•実は 𝑁 = Ω( 𝑀)なので計算量は 𝑂 𝑀32 である

ことがわかる