DDPC 2016 予選 解説

51
DISCO presents ディスカバリーチャンネル プログラミングコンテスト2016 予選 解説 AtCoder株式会社 3/19/15

Transcript of DDPC 2016 予選 解説

Page 1: DDPC 2016 予選 解説

DISCO presents ディスカバリーチャンネル プログラミングコンテスト2016 予選 解説

AtCoder株式会社

3/19/15

Page 2: DDPC 2016 予選 解説

A: DISCO presents ディスカバリーチャンネルプログラミングコンテスト 2016

Page 3: DDPC 2016 予選 解説

問題概要• DiscoPresentsDiscoveryChannelProgrammingContest2016という文字列を W文字ごとに改行して出力せよ

Page 4: DDPC 2016 予選 解説

解法•問題文に書かれている通り 1 行に W文字までしか出力しないようにすればよい

• for文などを用いて実装すればよい–余分な改行や空白文字をつけないように注意すること

Page 5: DDPC 2016 予選 解説

B: ディスコ社内ツアー

Page 6: DDPC 2016 予選 解説

問題概要•一方通行の環状道路のような N頂点の有向グラフが与えられる•頂点には 1 から Nのインデックスがついている•頂点 iにはある整数 Aiが書かれたスイッチがあり一度だけ押すことができる•頂点 1 から出発し,各頂点にあるスイッチ全てを押した状態で頂点 1 に戻る

–その際,スイッチに書かれた整数を,押した順序で並べた数列が広義単調増加列になるようにしたい•最低何周必要か?

Page 7: DDPC 2016 予選 解説

部分点1 ( N≦ 100, Aiは重複しうる)•それぞれの頂点にある整数たちを並べた数列をソートすることにより i番目に訪れることになる頂点が持つ値が分かる

•愚直に頂点を移動して何周必要か求めればよい–計算量は O(N2)

Page 8: DDPC 2016 予選 解説

部分点2 (与えられる数列が順列)• Nが最大 105と大きいので愚直に試すことはできない

•与えられる数列が順列なので,今見ている値が xなら次の値は x + 1 である• pos(x)をAi = xであるような頂点の位置としたとき,pos(x + 1) > pos(x) のとき,頂点 1 を通過しなくてはならない•計算量は O(N)

Page 9: DDPC 2016 予選 解説

満点 ( N≦ 105 , Aiは重複しうる)•順列の場合では次の位置が簡単に求められた

–各頂点が持つ値に重複や抜けがある場合はどうか?

1 2 3 4 5 61 5 3 5 1 3

Page 10: DDPC 2016 予選 解説

満点 ( N≦ 105 , Aiは重複しうる)•順列の場合では次の位置が簡単に求められた

–各頂点が持つ値に重複や抜けがある場合はどうか?

• 1 周目: 1, 5, 6 番目の頂点のスイッチを押す

1 2 3 4 5 61 5 3 5 1 3

Page 11: DDPC 2016 予選 解説

満点 ( N≦ 105 , Aiは重複しうる)•順列の場合では次の位置が簡単に求められた

–各頂点が持つ値に重複や抜けがある場合はどうか?

• 1 周目: 1, 5, 6 番目の頂点のスイッチを押す• 2 周目: 3, 4 番目の頂点のスイッチを押す

1 2 3 4 5 61 5 3 5 1 3

Page 12: DDPC 2016 予選 解説

満点 ( N≦ 105 , Aiは重複しうる)•順列の場合では次の位置が簡単に求められた

–各頂点が持つ値に重複や抜けがある場合はどうか?

• 1 周目: 1, 5, 6 番目の頂点のスイッチを押す• 2 周目: 3, 4 番目の頂点のスイッチを押す• 3 周目: 2 番目の頂点のスイッチを押す

1 2 3 4 5 61 5 3 5 1 3

Page 13: DDPC 2016 予選 解説

満点 ( N≦ 105 , Aiは重複しうる)•目的となる数列は{1, 1, 3, 3, 5, 5}になる•訪れる順序は以下のようになる

– 1 の始点は頂点 1 , 1 の終点は頂点 5,– 3 の始点は頂点 6 , 3 の終点は頂点 3– 5 の始点は頂点 4 , 5 の終点は頂点 2

• Aiの値ごとに数列を分けることを考える

1 2 3 4 5 61 5 3 5 1 3

Page 14: DDPC 2016 予選 解説

満点 ( N≦ 105 , Aiは重複しうる)• Aiの値ごとに数列を分けることを考えると,

– Ai = 1 で調べる必要がある頂点は 2 つ

1 2 3 4 5 65 5

3 31 1

Page 15: DDPC 2016 予選 解説

満点 ( N≦ 105 , Aiは重複しうる)• Aiの値ごとに数列を分けることを考えると,

– Ai = 1 で調べる必要がある頂点は 2 つ– Ai = 3 で調べる必要がある頂点は 2 つ

1 2 3 4 5 65 5

3 31 1

Page 16: DDPC 2016 予選 解説

満点 ( N≦ 105 , Aiは重複しうる)• Aiの値ごとに数列を分けることを考えると,

– Ai = 1 で調べる必要がある頂点は 2 つ– Ai = 3 で調べる必要がある頂点は 2 つ– Ai = 5で調べる必要がある頂点は 2 つ

1 2 3 4 5 65 5

3 31 1

Page 17: DDPC 2016 予選 解説

満点 ( N≦ 105 , Aiは重複しうる)•愚直に周回してもそれぞれの頂点を調べる回数は定数回で済む!

1 2 3 4 5 65 5

3 31 1

Page 18: DDPC 2016 予選 解説

満点解法まとめ•各頂点を Aiの値ごとに振り分ける

–鳩ノ巣ソートにより O(N) で行うことが可能• Ai = xであるような頂点たちに対し,最後に訪れた位置を覚えておいて,始点を検索 + シミュレーション

–このとき,それぞれの頂点を訪れるのは定数回で済む–よって計算量は O(N) で抑えられる

•全体の計算量はO(N)1 2 3 4 5 6

5 53 3

1 1

Page 19: DDPC 2016 予選 解説

C: アメージングな文字列は、きみが作る!

Page 20: DDPC 2016 予選 解説

問題概要•文字列 Sにちょうど K回以下の操作を行った文字列のうち、辞書順最小のものを求めよ

– Sの好きな位置に一文字挿入する– Sの好きな位置にある文字を一文字削除する– Sの好きな位置にある文字を別の文字に置換する

Page 21: DDPC 2016 予選 解説

部分点1: ( |S| ≦ 10, K≦ min(|S| – 1 , 4)) •どのような編集を行うか全て試す

–深さ優先探索などを用いればよい–ただし,辞書順最小の定義より,置換と挿入は以下の2 種類のみ考慮すればよい

• a以外の文字を aに置換する• aを挿入する• bや zなどの文字を使うより明らかに辞書順で小さくなる

– |S| も Kも小さいので十分間に合う

Page 22: DDPC 2016 予選 解説

部分点2: ( |S| ≦ 200)•先ほどの解法を動的計画法を用いて状態を減らす• dp(i, j)を Sの i文字目まで見て残り j回編集可能なときに作ることが可能な辞書順最小の文字列とする•現在の状態を dp(i, j)としたとき,遷移は以下の4種類

–今見ている文字をそのまま使用(dp(i + 1, j)へ)–今見ている文字を削除する(dp(i + 1, j – 1)へ)–今見ている文字の前に一文字挿入する(dp(i, j – 1)へ)–今見ている文字を置換する(dp(i + 1, j – 1)へ)

•状態数が O(|S|2),文字列の比較に O(|S|) かかるので,全体の計算量は O(|S|3)

Page 23: DDPC 2016 予選 解説

考察1• S = abcacbのときを考える

• K = 0: abcacb• K = 1: aabcacb• K = 2: aaaacb• K = 3: aaaaab• K = 4: aa• K = 5: a

Page 24: DDPC 2016 予選 解説

考察1•辞書順最小の定義より,以下の性質が分かる

– K回以下の操作で,Sを文字 a だけからなる文字列にすることが可能ならば⾧さを最小にするのがよい–そうでない場合は,先頭から連続する文字 aの個数を最大にするのがよい

Page 25: DDPC 2016 予選 解説

考察1•辞書順最小の定義より,以下の性質が分かる

– K回以下の操作で,Sを文字 a だけからなる文字列にすることが可能ならば⾧さを最小にするのがよい• Sに含まれる文字 a の個数と K の和が |S| 以上か調べればよい

–そうでない場合は,先頭から連続する文字 aの個数を最大にするのがよい• K = 2の例のように S中に含まれる a を使うことで, aの挿入よりaへの置換の方が先頭から連続する a の個数を増やせることがある

Page 26: DDPC 2016 予選 解説

考察2•先頭から連続する aの個数の最大値が,置換操作でも挿入操作でも変化しないとき,どうするか?• S = cacbxbyzzzz, K = 4 について考える

–一文字目を aに置換することで,先頭から連続する aの個数は最大 5 にすることが可能–残り 3 回,どのように置換,挿入を行うか?

Page 27: DDPC 2016 予選 解説

考察2•先頭から連続する aの個数の最大値が,置換操作でも挿入操作でも変化しないとき,どうするか?• S = cacbxbyzzzz, K = 4 について考える

–一文字目を aに置換することで,先頭から連続する aの個数は最大 5 にすることが可能–残り 3 回,どのように置換,挿入を行うか?

• 3 文字目の cを aに置換,その後先頭に aを 2 回挿入するのが最適

1 2 3 4 5 6 7 8 9 10 11c a c b x b y z z z z

c b x b y z z z zb x b y z z z z

x b y z z z z

Page 28: DDPC 2016 予選 解説

考察2•先頭から連続する aの個数の最大値が,置換操作でも挿入操作でも変化しないとき,どうするか?• S = cacbxbyzzzz, K = 4 について考える

–一文字目を aに置換することで,先頭から連続する aの個数は最大 5 にすることが可能–残り 3 回,どのように置換,挿入を行うか?

• 3 文字目の cを aに置換,その後先頭に aを 2 回挿入するのが最適• 候補となる i (3≦i≦5) 文字目を先頭とする接尾辞のうち辞書順最小のものを選ぶのが最適ということ

1 2 3 4 5 6 7 8 9 10 11c a c b x b y z z z z

c b x b y z z z zb x b y z z z z

x b y z z z z

Page 29: DDPC 2016 予選 解説

部分点 3: ( |S| ≦ 1,000)•文字 aだけからなる文字列が作れるならば可能な限り削除を行い⾧さ最小の文字列を作る

•先頭から連続する文字 aの個数が最大になるように,先頭から a以外の文字を aに置換する•先頭から連続する文字 aの個数が同じになるような範囲では,選べる接尾辞のうち最小のものを選ぶ

•文字列の比較に O(|S|),最大 O(|S|) 回比較を行うので,全体の計算量は O(|S|2)

Page 30: DDPC 2016 予選 解説

満点: ( |S| ≦ 300,000)•文字列 Sの接尾辞たちの辞書順における位置を高速に求めたい

•接尾辞配列(suffix array)と呼ばれるデータ構造が存在–これは Sの接尾辞たちの開始位置を要素とする配列を,接尾辞について辞書順に並び替えて得られる配列– O(|S|)で構築することが可能

Page 31: DDPC 2016 予選 解説

満点解法まとめ•文字 aだけからなる文字列が作れるならば可能な限り削除を行い⾧さ最小の文字列を作る

•先頭から連続する文字 aの個数が最大になるように,先頭から a以外の文字を aに置換する•先頭から連続する文字 aの個数が同じになるような範囲では,選べる接尾辞のうち最小のものを接尾辞配列に従って選ぶ

•全体の計算量は O(|S|)

Page 32: DDPC 2016 予選 解説

D: DDPC特別ビュッフェ

Page 33: DDPC 2016 予選 解説

問題概要• N個の非負整数からなる数列 Aと M個の非負整数からなる数列 Bが与えられる

• Aの要素 1 つと Bの要素 1 つを交換する操作をちょうど K回行ったときの ΣA ΣBを最大化せよ

Page 34: DDPC 2016 予選 解説

部分点1: (K = 1)•交換する組み合わせを愚直に全て試せばよい

•計算量は O(NM)

Page 35: DDPC 2016 予選 解説

考察1• Aと Bの要素の総和は常に一定

– ΣA = ΣBのとき,ΣAΣBが最大となる– Aから Bへ移動した要素の総和を a, BからA へ移動した要素の総和を b とすると,交換したあとの得点は(ΣA – a + b)(ΣB – b + a)で表せる

• K回の交換操作で出来る限り ΣAとΣBを近づけたい

Page 36: DDPC 2016 予選 解説

考察2• Aから Bへと移動した要素が k個のとき,Bから Aへと移動した要素は常に k個

–そうでないとすると,交換という操作に矛盾• K回の操作で, Aから Bへ何個移動させられるか?

– K = 1: 1– K > 1: 0, 1, 2, …, min(N, M, K)

• K > 1のとき, 0 以上 min(N, M, K)以下の任意の個数を移動可能• 交換操作は以下の 3 種類で考えればよい

– もともとA にあった要素を新たに 1 個移動させる– もともとA にあった要素を B からA へ 1 個移動させる– もともとA にあった要素同士を交換する

• N = 1, M = 1 のときは成り立たないが,あまり気にしなくてよい

Page 37: DDPC 2016 予選 解説

部分点2: (max(Ai, Bj) ≦ 55)•動的計画法を用いる

– ΣAが定まると ΣBも定まることに着目する– dp(i, j) = Bから Aに i個移動させる必要がある時の Aの要素の総和が jであるような操作はあるか?

• 典型的なナップサック問題– Aの要素を詰め終わったあと, i > min(N, M, K) であるdp(i, j) を全て偽にする

• min(N, M, K) より多くの要素を交換することは出来ない– Bの要素を詰めたあと,dp(0, x) が真である xについてx(C – x) の最大値を調べればよい

• ここで CはΣA + ΣB とする•計算量はO((N + M)2max(ΣA))

Page 38: DDPC 2016 予選 解説

満点: (max(Ai, Bj) ≦ 22,222)• bool 値を返すようなDPは状態数を削減可能なことがある• dp(j) = Aの要素の総和が jであるような, Bから Aに移動させる必要がある個数の集合,とする

• 部分点解法のdp(i, j) の iが取りうる値の集合(1, 2, 3, …, min(N, M, K))が返り値になっている• i番目のbitが 1 ならば部分点解法の dp(i, j) が真であることに対応• min(N, M, K) ≦ 55 より 64 bit符号付き整数の範囲に収まる

Page 39: DDPC 2016 予選 解説

満点: (max(Ai, Bj) ≦ 22,222)• dp(j) = Aの要素の総和が jであるような, Bから Aに移動させる必要がある個数の集合,とする• bit演算を用いて状態遷移を行う

• A = {1, 1, 3}, B = {1, 2, 4}, K = 2 の例を示す• はじめ,Aから 1 つも移動させないという状態のみが真

ΣA 0 1 2 3 4 5 6 7 8 9dp(ΣA) 0000 0000 0000 0000 0000 0001 0000 0000 0000 0000

Page 40: DDPC 2016 予選 解説

満点: (max(Ai, Bj) ≦ 22,222)• dp(j) = Aの要素の総和が jであるような, Bから Aに移動させる必要がある個数の集合,とする• bit演算を用いて状態遷移を行う

• A = {1, 1, 3}, B = {1, 2, 4}, K = 2 の例を示す• はじめ,Aから 1 つも移動させないという状態のみが真• 遷移は dp(x) を 1 bit左にシフトしたものとの論理和で表現可能

– dp(x – Ai) = dp(x – Ai) or (dp(x) << 1) で表せる• A0を移動させるかどうかで遷移させる

ΣA 0 1 2 3 4 5 6 7 8 9dp(ΣA) 0000 0000 0000 0000 0010 0001 0000 0000 0000 0000

Page 41: DDPC 2016 予選 解説

満点: (max(Ai, Bj) ≦ 22,222)• dp(j) = Aの要素の総和が jであるような, Bから Aに移動させる必要がある個数の集合,とする• bit演算を用いて状態遷移を行う

• A = {1, 1, 3}, B = {1, 2, 4}, K = 2 の例を示す• はじめ,Aから 1 つも移動させないという状態のみが真• 遷移は dp(x) を 1 bit左にシフトしたものとの論理和で表現可能

– dp(x – Ai) = dp(x – Ai) or (dp(x) << 1) で表せる• A0を移動させるかどうかで遷移させる• A1を移動させるかどうかで遷移させる

ΣA 0 1 2 3 4 5 6 7 8 9dp(ΣA) 0000 0000 0000 0100 0010 0001 0000 0000 0000 0000

Page 42: DDPC 2016 予選 解説

満点: (max(Ai, Bj) ≦ 22,222)• dp(j) = Aの要素の総和が jであるような, Bから Aに移動させる必要がある個数の集合,とする• bit演算を用いて状態遷移を行う

• A = {1, 1, 3}, B = {1, 2, 4}, K = 2 の例を示す• はじめ,Aから 1 つも移動させないという状態のみが真• 遷移は dp(x) を 1 bit左にシフトしたものとの論理和で表現可能

– dp(x – Ai) = dp(x – Ai) or (dp(x) << 1) で表せる• A0を移動させるかどうかで遷移させる• A1を移動させるかどうかで遷移させる• A2を移動させるかどうかで遷移させるΣA 0 1 2 3 4 5 6 7 8 9

dp(ΣA) 1000 0100 0010 0100 0010 0001 0000 0000 0000 0000

Page 43: DDPC 2016 予選 解説

満点: (max(Ai, Bj) ≦ 22,222)• dp(j) = Aの要素の総和が jであるような, Bから Aに移動させる必要がある個数の集合,とする• bit演算を用いて状態遷移を行う

• A = {1, 1, 3}, B = {1, 2, 4}, K = 2 の例を示す• はじめ,Aから 1 つも移動させないという状態のみが真• 遷移は dp(x) を 1 bit左にシフトしたものとの論理和で表現可能

– dp(x – Ai) = dp(x – Ai) or (dp(x) << 1) で表せる• A0を移動させるかどうかで遷移させる• A1を移動させるかどうかで遷移させる• A2を移動させるかどうかで遷移させるΣA 0 1 2 3 4 5 6 7 8 9

dp(ΣA) 1000 0100 0010 0100 0010 0001 0000 0000 0000 0000

Page 44: DDPC 2016 予選 解説

満点: (max(Ai, Bj) ≦ 22,222)• A = {1, 1, 3}, B = {1, 2, 4}, K = 2• Aの要素を詰め終わったあと, i > min(N, M, K) である dp(i, j) を全て偽にする,という操作をbit演算で表現したい

ΣA 0 1 2 3 4 5 6 7 8 9dp(ΣA) 1000 0100 0010 0100 0010 0001 0000 0000 0000 0000

Page 45: DDPC 2016 予選 解説

満点: (max(Ai, Bj) ≦ 22,222)• A = {1, 1, 3}, B = {1, 2, 4}, K = 2• Aの要素を詰め終わったあと, i > min(N, M, K) である dp(i, j) を全て偽にする,という操作をbit演算で表現したい•下から min( N, M, K ) + 1 個のbitが 1であるマスクと論理積をとってやればよい!

–この例だと dp(x) = dp(x) and 0111 で表せる

ΣA 0 1 2 3 4 5 6 7 8 9dp(ΣA) 0000 0100 0010 0100 0010 0001 0000 0000 0000 0000

Page 46: DDPC 2016 予選 解説

満点: (max(Ai, Bj) ≦ 22,222)• A = {1, 1, 3}, B = {1, 2, 4}, K = 2• Bの要素を詰める遷移を Aのときと同様に行う

ΣA 0 1 2 3 4 5 6 7 8 9dp(ΣA) 0000 0100 0010 0100 0010 0001 0000 0000 0000 0000

Page 47: DDPC 2016 予選 解説

満点: (max(Ai, Bj) ≦ 22,222)• A = {1, 1, 3}, B = {1, 2, 4}, K = 2• Bの要素を詰める遷移を Aのときと同様に行う

• 遷移は dp(x) を 1 bit右にシフトしたものとの論理和で表現可能– dp(x + Bi) = dp(x + Bi) or (dp(x) >> 1) で表せる

• B0を移動させるかどうかで遷移させる

ΣA 0 1 2 3 4 5 6 7 8 9dp(ΣA) 0000 0100 0010 0101 0010 0001 0000 0000 0000 0000

Page 48: DDPC 2016 予選 解説

満点: (max(Ai, Bj) ≦ 22,222)• A = {1, 1, 3}, B = {1, 2, 4}, K = 2• Bの要素を詰める遷移を Aのときと同様に行う

• 遷移は dp(x) を 1 bit右にシフトしたものとの論理和で表現可能– dp(x + Bi) = dp(x + Bi) or (dp(x) >> 1) で表せる

• B0を移動させるかどうかで遷移させる• B1を移動させるかどうかで遷移させる

ΣA 0 1 2 3 4 5 6 7 8 9dp(ΣA) 0000 0100 0010 0111 0011 0011 0001 0000 0000 0000

Page 49: DDPC 2016 予選 解説

満点: (max(Ai, Bj) ≦ 22,222)• A = {1, 1, 3}, B = {1, 2, 4}, K = 2• Bの要素を詰める遷移を Aのときと同様に行う

• 遷移は dp(x) を 1 bit右にシフトしたものとの論理和で表現可能– dp(x + Bi) = dp(x + Bi) or (dp(x) >> 1) で表せる

• B0を移動させるかどうかで遷移させる• B1を移動させるかどうかで遷移させる• B2を移動させるかどうかで遷移させる

ΣA 0 1 2 3 4 5 6 7 8 9dp(ΣA) 0000 0100 0010 0111 0011 0011 0001 0011 0001 0001

Page 50: DDPC 2016 予選 解説

満点: (max(Ai, Bj) ≦ 22,222)• A = {1, 1, 3}, B = {1, 2, 4}, K = 2•全ての遷移を完了した

–このとき最下位bitが 1 ならば,そのような交換が存在する–そのような全ての xについて x(C – x) の最大値を調べればよい

• ここで CはΣA + ΣB とする

ΣA 0 1 2 3 4 5 6 7 8 9dp(ΣA) 0000 0100 0010 0111 0011 0011 0001 0011 0001 0001

Page 51: DDPC 2016 予選 解説

満点解法まとめ• bool 値を返すようなDPは状態数を削減可能なことがある• dp(j) = Aの要素の総和が jであるような, Bから Aに移動させる必要がある個数の集合,とする

• 部分点解法のdp(i, j) の iが取りうる値の集合(1, 2, 3, …, min(N, M, K))が返り値になっている• i番目のbitが 1 ならば部分点解法の dp(i, j) が真であることに対応

• bit演算を使ってDPを行うことで全ての iについてまとめて計算を行うことで高速化が可能

•計算量は O((N + M)max(ΣA))