24
CODE FESTIVAL 2014 エキシビジョン 解説 AtCoder株式会社 代表取締役 高橋 直大 2014/11/8 1

CODE FESTIVAL 2014 エキシビジョン 解説

Embed Size (px)

DESCRIPTION

CODE FESTIVAL 2014 エキシビジョン 解説

Citation preview

Page 1: CODE FESTIVAL 2014 エキシビジョン 解説

CODE FESTIVAL 2014 エキシビジョン解説

AtCoder株式会社代表取締役

高橋直大

2014/11/8 1

Page 2: CODE FESTIVAL 2014 エキシビジョン 解説

©AtCoder Inc. All rights reserved. 2

A問題 パズル

2014/11/8 2

Page 3: CODE FESTIVAL 2014 エキシビジョン 解説

問題概要

• 頂点数N(≦2000),辺数M(≦2000)のグラフが与えられる。きさ3のクリークを3つ組と呼び,3つ組の値を図のように「回転」できる

• 最初,頂点1に番号1,頂点2に番号2,…,頂点Nに番号Nが割り振られている

• 回転を任意の回数繰り返して,与えられる目標の番号付けにできるか?

1

3 2

4

3

2 1

4(1,2,3)を回転したとき

Page 4: CODE FESTIVAL 2014 エキシビジョン 解説

考察

• 3つ組構成辺のみで構成される連結な大きさのグラフで全探索してみると,状態空間は2つに分断されていることが分かる

→偶奇性が存在する

• 上記のグラフにおいて,連結であれば,直接3つ組でなくとも,任意の頂点を3つ組とみなすことができそう→ できる

4

52 1

3

67 8

4

52 1

3

67 8

3つ組構成辺のみで構成されるグラフ(右)

Page 5: CODE FESTIVAL 2014 エキシビジョン 解説

©AtCoder Inc. All rights reserved. 5

B問題 かっこつけ

2014/11/8 5

Page 6: CODE FESTIVAL 2014 エキシビジョン 解説

問題概要

● 開きカッコと閉じカッコからなる文字列Sがある

● 以下「文字列」とはカッコのみからなるものとする

● Sに以下のような操作を合わせてQ回行う

● 開きカッコや閉じカッコを挿入する

● ある文字を削除する

● ある部分文字列「カッコ悪さ」を求める

● 1 ≦ |S| ≦ 10^5

● 1 ≦ Q ≦ 10^5

Page 7: CODE FESTIVAL 2014 エキシビジョン 解説

考察

● 文字列の「カッコ悪さ」とは?

● 文字列からいくつか文字を取り去ってカッコの対応を整合にするときに、取り去る文字の個数の最小値

● どうすれば求めることができる?

Page 8: CODE FESTIVAL 2014 エキシビジョン 解説

考察

● カッコを扱うときに多用される変換

● '(' → +1 ')' → -1

● (())()() → +1, +1, -1, -1, +1, -1, +1, -1

● 累積和を取る

● (())()() → 1, 2, 1, 0, 1, 0, 1, 0

● 変換して累積和をとった後の配列をAとする

Page 9: CODE FESTIVAL 2014 エキシビジョン 解説

考察

● (())()() → 1, 2, 1, 0, 1, 0, 1, 0

● ある文字列Sのカッコの対応が整合であることの必要十分条件は

Aの要素がすべて非負 かつ Aの最後の要素が0

● これは以下のように言い換えることが出来る

Aの最小値が0 かつ Aの最後の要素が0

● 「カッコ悪さ」もAの値から求めることが出来る

Page 10: CODE FESTIVAL 2014 エキシビジョン 解説

考察

● ある文字列Sから閉じカッコを取り除くと、Aのそれ以降の値が+1される

● これによってAの最小値を0に調節することが出来る

● ある文字列Sから開きカッコを取り除くと、Aのそれ以降の値が-1される

● これによってAの最後の値を0にすることが出来る

Page 11: CODE FESTIVAL 2014 エキシビジョン 解説

考察

● この操作によってある文字列Sを整合にすると(Aの最後の値) – 2*(Aの最小値)個の文字を取り去ることになる。

● 実はこれより少ない個数の文字を取り除くことでは文字列を整合にできない

● Aの最後の値とAの最小値を一致させつつ、その値を0にするためにはこれより少なくできない

● よってこの値が「カッコ悪さ」となる

Page 12: CODE FESTIVAL 2014 エキシビジョン 解説

考察

● 部分文字列の「カッコ悪さ」についても同様に考えることが出来る

● 文字列Sのl文字目からr文字目の「カッコ悪さ」は

● A[l] + A[r] – 2*(A[l]~A[r]の中の最小値)

● になる

Page 13: CODE FESTIVAL 2014 エキシビジョン 解説

考察

● よって数列Aに対して以下の操作ができれば良い

● ある範囲に一様に値を足す

● Aのある場所に値を挿入する

● Aのある場所の値を削除する

● ある範囲の値の最小値を求める

● Aのある場所の値の参照

Page 14: CODE FESTIVAL 2014 エキシビジョン 解説

アルゴリズム

● よって数列Aに対して以下の操作ができれば良い

● ある範囲に一様に値を足す

● Aのある場所に値を挿入する

● Aのある場所の値を削除する

● ある範囲の値の最小値を求める

● Aのある場所の値の参照

● これらを高速に行えるデータ構造は?

Page 15: CODE FESTIVAL 2014 エキシビジョン 解説

アルゴリズム

● 平衡二分探索木!!

Page 16: CODE FESTIVAL 2014 エキシビジョン 解説

アルゴリズム

● 平衡二分探索木!!

● 実装が重い

● エンバグしやすい

● 2問1時間のコンテストで組むもの(組めるもの)ではない

● どうすればよいのか?

Page 17: CODE FESTIVAL 2014 エキシビジョン 解説

アルゴリズム

● 平方分割!!

Page 18: CODE FESTIVAL 2014 エキシビジョン 解説

アルゴリズム

● 平方分割!!

● 数列AをB個ずつのバケットに区切って処理する

● 各バケットはその範囲に一様に足されている値を保持する

● 値が挿入、削除されたらそのバケット内で単純に挿入、削除するO(B)

● クエリB回に一回、バケットの各サイズがB

個ずつになるように再構成する

Page 19: CODE FESTIVAL 2014 エキシビジョン 解説

アルゴリズム

● 計算量

● バケットのサイズ

– B回に一度サイズを調整するので、バケットのサイズは0~2Bに収まっている。つまりO(B)

● バケットの個数

– バケットの個数は再構築の時以外かわらない。最大でAの要素数 / B個ある。全クエリが挿入だったとしてもバケットの個数は(N+Q) / B

Page 20: CODE FESTIVAL 2014 エキシビジョン 解説

アルゴリズム

● 計算量

● 挿入、削除、値の参照

– O(バケットの個数)でバケットを探索

– O(バケットのサイズ)でバケット内で挿入,削除,参照

– 合わせてO(B+(N+Q)/B)

● 一様に足す、最小値を求める

– O(バケットの個数 + バケットのサイズ)

– O(B+(N+Q)/B)

● 再構築

– O(N)

– 再構築の回数はN/B回

Page 21: CODE FESTIVAL 2014 エキシビジョン 解説

アルゴリズム

● 全体の計算量

● カッコの挿入、削除(値の挿入、削除、一様に足す)

– O(Q × (B + N/B))

● カッコ悪さを求める(参照、最小値)

– O(Q × (B + N/B))

● 再構築

– O(N/B × N)

Page 22: CODE FESTIVAL 2014 エキシビジョン 解説

アルゴリズム

● まとめると

● O(Q×(B+N/B) + (N^2/B))

● N,Q≦10^5なのでB=sqrt(10^5)≒340くらいにするのが最適

● O(Q×340+N^2/340)

● 間に合う

Page 23: CODE FESTIVAL 2014 エキシビジョン 解説

実装

● バケットのサイズはたかだか2Bで、バケットの個数はたかだか(N+Q)/Bなので動的配列(vector)等をつかわなくとも普通の配列で実装可能です

Page 24: CODE FESTIVAL 2014 エキシビジョン 解説

2014/11/8 24