atcoder regular contest 022 解説

46
AtCoder Regular Contest 022 解説 AtCoder株式会社 2014/5/3 1

Upload: atcoder-inc

Post on 02-Jul-2015

1.535 views

Category:

Education


1 download

DESCRIPTION

AtCoder Regular Contest 022 解説

TRANSCRIPT

Page 1: AtCoder Regular Contest 022 解説

AtCoder Regular Contest 022 解説

AtCoder株式会社

2014/5/3 1

Page 2: AtCoder Regular Contest 022 解説

A問題スーパーICT高校生

Page 3: AtCoder Regular Contest 022 解説

A-問題概要● 文字列Sが与えられる● Sからいくつか文字を省いて”ICT”を作れるか判定せよ

● 大文字小文字は区別しない

1≦∣S∣≦100

Page 4: AtCoder Regular Contest 022 解説

A-想定解● 残す'I'はSの中で一番最初の'I'でよい。● 残す'C'はその'I'以降で一番最初の'C'でよい。● 残す'T'はその'C'以降で一番最初の'T'でよい。● 順番に貪欲的に文字を取っていく。● O(|S|)

– 想定解

Page 5: AtCoder Regular Contest 022 解説

A-想定解2● 今回は探索する'ICT'が3文字なので、さまざまなその場しのぎのアルゴリズムが考えられる。

● 3文字を全通り試す

– O(|S|^3)● 'C'を決めてその左右に'I'や'T'があるか判定

– O(|S|^2)● 最初の'I'と最後の'T'の間に'C'があるかどうか判定

– O(|S|)

Page 6: AtCoder Regular Contest 022 解説

A-大文字小文字● この問題では大文字小文字を区別しない● 知るかぎり、どのプログラミング言語でも大文字と小文字は別物と判断されるので、何とかしなければならない– 自前の比較関数を作る– あらかじめ全て大文字か小文字に揃える

Page 7: AtCoder Regular Contest 022 解説

B問題細長いお菓子

Page 8: AtCoder Regular Contest 022 解説

問題概要

• お菓子がうんぬんと言っていますが要するに、• 長さNの数列Aが与えられるので、同じ数字を2つ以上含まない最長の区間の長さを求めよ。

• 部分点(50点): N ≦ 100、Ai ≦ 100• 部分点(99点): N ≦ 1000、Ai ≦ 1000• 満点:N ≦ 10^5、Ai ≦ 10^5

Page 9: AtCoder Regular Contest 022 解説

部分点(50点)N ≦ 100

• 区間の左端と右端を全て試し、その区間の中に同じ数字が2つ以上含まるかどうかを調べる。

→「同じ数字が2つ以上含まれるかどうか」を高速に判定したい。

Page 10: AtCoder Regular Contest 022 解説

• 方法1:頻度を計算しておく• 「それぞれの数字がいくつ含まれるか」を、配列を使って求めておき、2つ以上含まれる数字がないかを調べる。

for (int i = L; i <= R; i++) freq[A[i]]++;

頻度の計算の例

判定のやり方

Page 11: AtCoder Regular Contest 022 解説

• 方法2:集合を扱うデータ構造を使う• 例えばsetやDictionaryなど。• 集合に数字をどんどん追加していき、すでに追加されている数字があれば、ダメ。

判定のやり方

Page 12: AtCoder Regular Contest 022 解説

部分点(99点)N ≦ 1000

• 区間の左端だけを全部試し、それぞれに対してどれだけ区間をのばすことが出来るかを調べる。

• ひとつずつ数字を見ていき、その数字がすでに区間の中に入っていたらその時点でストップ、とする。

• 判定の方法は50点の部分点の方法と同様の方法を使えば良い。(方法1でも方法2でも良い)

Page 13: AtCoder Regular Contest 022 解説

満点 N ≦ 10^5

• 尺取法を使う。

• 判定の部分に”方法2”を使う場合は、データ構造が削除クエリに対応している必要があります。

l = 0;for (r = 0; r < N; r++) { while ([l,r]に同じ数字が2つ以上含まれている) l++; answer = max(answer, r - l + 1);}

尺取法の例

Page 14: AtCoder Regular Contest 022 解説

C問題ロミオとジュリエット

Page 15: AtCoder Regular Contest 022 解説

問題概要

• 要するに、• 頂点数Nの木が与えられるので、距離が最長となる頂点のペアを1つ見つけよ。

• 部分点(40点):N ≦ 1000• 満点:N ≦ 10^5

Page 16: AtCoder Regular Contest 022 解説

部分点(40点)N ≦ 1000

• 片方の頂点を全て試し、その頂点から最も遠い頂点を探す。

• 最も遠い頂点を探すためにはBFSを使えば良い。木なのでDFSを使ってもOK。

• 木の上ではDFSをすることが多いので、DFSで書けるようになっておくのがオススメです。

Page 17: AtCoder Regular Contest 022 解説

満点 N ≦ 10^5

• 2頂点間の最大の距離=直径と言います。• すなわちこの問題は、木の直径を求める問題です。• 木の直径を求めるアルゴリズムを2通りほど紹介します。

Page 18: AtCoder Regular Contest 022 解説

木の直径の求め方その1

• 簡単な木DPをする。• とりあえず根を適当に決めて根付き木にします。• 任意の2頂点間の移動は「まず根の方向にいくつか辿り、根から離れる方向にいくつか辿る」となっています。

• LCA(Lowest Common Ancestor)に注目します。(移動で通る頂点のうち最も根に近い頂点がLCAです。)

4 5

1

6

2 3

87

Page 19: AtCoder Regular Contest 022 解説

木の直径の求め方その1

• ある頂点(Vとする)をLCAとする頂点のペアのうち、最も距離が離れているものは、

• 「あるVの子の子孫のうち最もVから遠い頂点」(Vの子の数だけある)と「V」のうち、Vから遠い順に2つ選んだ時の頂点のペアになります。

• これをボトムアップに(葉から順に)計算して行けば良い。

4 5

1

6

2 3

87

Page 20: AtCoder Regular Contest 022 解説

木の直径の求め方その2

• こちらは、方法としてはとても単純です。• まず、頂点を適当に選んでWとします。• Wから最も遠い頂点を探してVとします。• Vから最も遠い頂点を探してUとします。• すると、VとUが答えになっています。

Page 21: AtCoder Regular Contest 022 解説

木の直径の求め方その2(仕組みについて)

• 木には中心というものがあります。• 木の中心とは、直径の中心のことです。→ 中心は辺上の点になることもあります。

• 全ての直径は木の中心を通ります。→ 中心から各頂点への距離は直径/2以下で ・・・と考えたりすると証明できます。

V U

W

Page 22: AtCoder Regular Contest 022 解説

木の直径の求め方その2(仕組みについて)

• Vは中心をまたいでWと反対側にある最も遠い頂点であるため、直径の端点となる。

• Uは中心をまたいでVと反対側にある最も遠い頂点であるため、直径のもう片方の端点となる。

• というからくりになっています。

V U

W

Page 23: AtCoder Regular Contest 022 解説

まとめ

• 1つ目の方法は汎用性が高いテクニックなので、書けるようになっておいた方が良いでしょう。

• 2つ目の方法は、直径を求める際には楽な方法なので、覚えておいて損は無いでしょう。

Page 24: AtCoder Regular Contest 022 解説

D問題スプリンクラー

Page 25: AtCoder Regular Contest 022 解説

D-問題概要● 直交座標上にN個の格子点(x, y)が与えられる● 各格子点に対して、それを中心として原点を通

る円を考える● いずれかの円に含まれる格子点の個数を求めよ● N ≦ 10^5● -10^5 ≦ x, y ≦ 10^5

Page 26: AtCoder Regular Contest 022 解説

D-部分点1● N ≦ 100● -100 ≦ x, y ≦ 100● 頂点と円の組み合わせを全て調べても間に合う● O(N |x| |y|)

– 10点が得られる

Page 27: AtCoder Regular Contest 022 解説

D-部分点2● N ≦ 1,000● -1,000 ≦ x, y ≦ 1,000● 全頂点の走査なら可能そう● いろいろな図形を重ねた時に、何枚重なってい

るか数える都合のいいアルゴリズムがあった気がする・・・

Page 28: AtCoder Regular Contest 022 解説

D-部分点2

累積和

Page 29: AtCoder Regular Contest 022 解説

D-部分点2● 長方形ではないのでいつもの二次元累積和は使

えない– 一次元に分けたらできる

● 円周の左側を+1 右側を-1する

Page 30: AtCoder Regular Contest 022 解説

D-部分点2● +1や-1する点は円1つあたり、たかだかO(半

径)個くらい– 今回なら 1000 * √2

● 総計算量はO(N max(|x|, |y|))– 計30点が得られる

Page 31: AtCoder Regular Contest 022 解説

D-考察● 累積和をすると、そこにいくつの円が重なって

いるかという余計な情報も求めることになる– 無駄

● 1個以上重なっているかどうかさえわかればいい– 無駄な+1, -1をしないように削る

Page 32: AtCoder Regular Contest 022 解説

D-考察● 無駄な+1, -1の例

Page 33: AtCoder Regular Contest 022 解説

D-考察● どうやら完全に外側に接している部分付近だけ

の+1, -1で充分● 外周さえ求まれば

なんとかなりそう● どうすれば

求まるのか・・・

Page 34: AtCoder Regular Contest 022 解説

D-部分点2

凸包

Page 35: AtCoder Regular Contest 022 解説

D-考察● 点A,点Bと三角形OAB内の点C● Cを中心とする円はAもしくはBを中心とする円

に完全に覆われる● Cは考えなくて良い

Page 36: AtCoder Regular Contest 022 解説

D-考察 部分点3● どの三角形の内側にも入らない点だけを考えれ

ば良い– つまり凸包上にある頂点だけを考える

● 頂点は全て格子点にあるので凸包上にある点はたかだか√|x|個くらい

● 凸包で頂点を減らしてimos法をすれば良い– O(x log x + x√|x|) 計60点が得られる

Page 37: AtCoder Regular Contest 022 解説

D-さらに処理を少なく● 凸包上の点を中心とする円でも、その円周が全

て外側に触れている(外周)わけではない– 外周のところだけで計算してよい

● 円どうしの交点、つまり円弧の両端が求まれば良い

● 交差する円は、凸包の多角形における隣り合う頂点に対応する円だけ– 幾何の計算をいくらかすれば交点はもとまる

Page 38: AtCoder Regular Contest 022 解説

D-外周だけを考える● 各円弧の両端が求まれば、その間に含まれる範

囲だけ考えれば良い。– ある点がある円弧に含まれるかどうかは凸包と同様

に外積を使えば良い● 外周だけ考えるのは何とかなりそうだけれども

はたしてそれで満点の制約において間に合うのか?

Page 39: AtCoder Regular Contest 022 解説

D-計算量● 累積和において別々に考えるときに、y=k(k

は整数)となる直線で輪切りにして考えるとする。

● そのとき、各直線上には左端と右端がいくつか乗る。それを計算すれば各直線上の条件に合う花の数が求まる。

Page 40: AtCoder Regular Contest 022 解説

D-計算量● 右端や左端は外周がy=k(kは整数)と交わる点

の数だけある。● 外周を一周りするときにy=k(kは整数)と何回

交わるかを求めれば、計算量が求まる。

Page 41: AtCoder Regular Contest 022 解説

D-計算量● 各円弧の両端と原点を結んだ三角形の原点の部

分の内角は、その円弧の円周角に当たる。– 全外周の円周角の総和はたかだか360°– よって中心角の総和はたかだか720°

● 円の半径は|x|*√2以下なので、外周の上限は|x|*4√2 * (円周率)

● 今回の問題ではおおよそ2,000,000くらい

Page 42: AtCoder Regular Contest 022 解説

D-計算量● 外周をたどって一回りする時、いろいろなy=k

と交わる。● いまy=aと交わったとする。その次に交わるの

はy=a+1, y=a-1, y=aのいずれかである

Page 43: AtCoder Regular Contest 022 解説

D-計算量● 次にy=a+1,y=a-1と交わることは、外周を1

以上進んでいるので2,000,000回しか起こらない

● 次にy=aと交わることは、下図のような場合のみ。共にO(N)回接線がx軸と平行になる付近 違う円弧と変わる付近

Page 44: AtCoder Regular Contest 022 解説

D-計算量● よって、外周とy=k(kは整数)との交点はたか

だか2,000,000個くらいしかないので全列挙しても十分間に合う– 想定解

Page 45: AtCoder Regular Contest 022 解説

D-想定解まとめ● スプリンクラーと世界一の花で凸包を取る。● 凸包上の点とそれに対応する円を順番に見てい

き、隣の円との交点を求め、外周となる範囲を得る

● 外周上を順番に走査してy=k(kは整数)との交点を全て列挙する

● 左端と右端が全て求まるので適当に各yについて引き算をして、総和を取ると答えになる

Page 46: AtCoder Regular Contest 022 解説

D-計算量まとめ● 凸包でO(N log N)

– バケツソートによる基数ソートをすればO(N)– 凸包上の点の数をMとする M = O(√|x|)

● 円どうしの交点を求めるのにO(M)● y=k(kは整数)との交点を全列挙するのにO(|x|

*4√2 * 円周率)● おおよそ10^6オーダー