第2回  早稲⽥田⼤大学プログラミングコンテスト


    G: だるま落落とし
    keyword: ⼆二分探索索、データ構造
問題概要


a[n-1]      .
            .
            .

 a[2]

 a[1]


 a[0]           2H : ハンマーの幅
問題概要


a[n-1]      .
            .
            .
                          arg

 a[2]

 a[1]


 a[0]                      2H : ハンマーの幅



     [!] addクエリ : ⾼高さargのブロックを上に追加
問題概要


a[n-1]      .
            .
            .

 a[2]
                         H
 a[1]
                         H
 a[0]              arg


     [!] challengeクエリ : ⾼高さarg(>=H)で叩く
問題概要


a[n-1]      .
            .
            .

  だるま落落としをシミュレーションし、
 a[2]

  クエリをたくさん処理理してください。
 a[1]
           H
                         H
 a[0]              arg


     [!] challengeクエリ : ⾼高さarg(>=H)で叩く
制約
¤  制約
  ¤  初期ブロックの数 <= 100,000
  ¤  クエリの数  <= 100,000
愚直にやると
¤  配列列による実装
 ¤  配列列の各要素にだるまの⾼高さを持つ

¤  各クエリに対する処理理
 ¤  addクエリ
     ¤  配列列の末尾に追加 / O(1)
 ¤  challengeクエリ
   ¤  どのブロックが叩かれるか探す / O(N)
   ¤  “go”の場合、ブロックを詰める / O(N)

¤  クエリ数が多いのでこれでは間に合わない。
まず考えるべきこと
¤  ⾼高さの累累積和を持っておく
 ¤  addクエリ
     ¤  配列列の末尾に追加 / O(1)
 ¤  challengeクエリ
   ¤  どのブロックが叩かれるか探す / ⼆二分探索索でO(logN)
   ¤  “go”の場合、ブロックを詰める / O(N)


¤  ハンマーの上⾯面と下⾯面に当たるブロックの位置を探す。
 ¤  両者が同じなら “go”  違うなら “stop”

¤  ブロックを詰める操作をなんとかして⼯工夫したい。
重要な考え⽅方


a[n-1]        .
              .
              .
                            a[n-2]   .
 a[2]
                                     .
                                     .
 a[1]        削除
                             a[1]

 a[0]                        a[0]



         [!] a[1] を抜かして配列列を詰めた
重要な考え⽅方


a[n-1]      .
            .
            .
                                a[n-1]
                                         .
 a[2]                                    .
                                         .
 a[1]      ⾼高さを
                                 a[2]
            0に
                     a[1] = 0
 a[0]                            a[0]



    [!] a[1] を 0 にした ⇒ 配列列サイズは変えなくていい
解決策
¤  Fenwick Tree(BIT : Binary Indexed Treeとも)
  ¤  累累積和を効率率率よく処理理できるデータ構造!

¤  以下のことがそれぞれO(logN)で可能
  ¤  a[1]〜~a[k] までの累累積和を求める
  ¤  a[k] の値を更更新する

¤  ⇒ 今回の⽤用途にピッタリ!
  ¤  addクエリ
     ¤  ブロックの総数を覚えておいて、末尾位置に更更新クエリ
  ¤  challengeクエリ
      ¤  累累積和クエリを使って⼆二分探索索し、位置を求める
     ¤  “go” なら、⾒見見つけた位置のブロックに更更新クエリ
⼀一番上のブロックを叩く時
¤  上部に処理理後ブロック(サイズが0)が溜溜まると誤判定の可能性が!

¤  ⼀一番上かどうかの判定
 ¤  シミュレーション中、
     だるまの⾼高さを持っておく(Hとおく)
 ¤  ハンマーの下⾯面位置に当たる
     ブロックの最下部位置を  X とする
                                  サイズ0
                                  = 処理理後
 ¤  X + (ブロックの⾼高さ) = H なら⼀一番上!


                                  ⼀一番上
解法
¤  クエリを先読みして、登場するブロック数をカウント

¤  そのサイズでFenwick Treeを初期化

¤  クエリが来るたびに、以下の処理理をする
    ¤  addクエリ
        ¤  現在の末尾位置にブロックのサイズで更更新クエリ
    ¤  challengeクエリ
        ¤  累累積和クエリを使って⼆二分探索索し、位置を求める
      ¤  “go” なら、⾒見見つけた位置のブロックに更更新クエリ
統計
¤  First AC : hos.lyric* (56:09)

¤  正解数 : 31
   ¤  通した⼈人(31/205) : 15%
   ¤  ACだった解答(31/281) : 11%

WUPC2nd G問題

  • 1.
    第2回  早稲⽥田⼤大学プログラミングコンテスト G: だるま落落とし keyword: ⼆二分探索索、データ構造
  • 2.
    問題概要 a[n-1] . . . a[2] a[1] a[0] 2H : ハンマーの幅
  • 3.
    問題概要 a[n-1] . . . arg a[2] a[1] a[0] 2H : ハンマーの幅 [!] addクエリ : ⾼高さargのブロックを上に追加
  • 4.
    問題概要 a[n-1] . . . a[2] H a[1] H a[0] arg [!] challengeクエリ : ⾼高さarg(>=H)で叩く
  • 5.
    問題概要 a[n-1] . . . だるま落落としをシミュレーションし、 a[2] クエリをたくさん処理理してください。 a[1] H H a[0] arg [!] challengeクエリ : ⾼高さarg(>=H)で叩く
  • 6.
    制約 ¤  制約 ¤  初期ブロックの数 <= 100,000 ¤  クエリの数  <= 100,000
  • 7.
    愚直にやると ¤  配列列による実装 ¤ 配列列の各要素にだるまの⾼高さを持つ ¤  各クエリに対する処理理 ¤  addクエリ ¤  配列列の末尾に追加 / O(1) ¤  challengeクエリ ¤  どのブロックが叩かれるか探す / O(N) ¤  “go”の場合、ブロックを詰める / O(N) ¤  クエリ数が多いのでこれでは間に合わない。
  • 8.
    まず考えるべきこと ¤  ⾼高さの累累積和を持っておく ¤ addクエリ ¤  配列列の末尾に追加 / O(1) ¤  challengeクエリ ¤  どのブロックが叩かれるか探す / ⼆二分探索索でO(logN) ¤  “go”の場合、ブロックを詰める / O(N) ¤  ハンマーの上⾯面と下⾯面に当たるブロックの位置を探す。 ¤  両者が同じなら “go”  違うなら “stop” ¤  ブロックを詰める操作をなんとかして⼯工夫したい。
  • 9.
    重要な考え⽅方 a[n-1] . . . a[n-2] . a[2] . . a[1] 削除 a[1] a[0] a[0] [!] a[1] を抜かして配列列を詰めた
  • 10.
    重要な考え⽅方 a[n-1] . . . a[n-1] . a[2] . . a[1] ⾼高さを a[2] 0に a[1] = 0 a[0] a[0] [!] a[1] を 0 にした ⇒ 配列列サイズは変えなくていい
  • 11.
    解決策 ¤  Fenwick Tree(BIT: Binary Indexed Treeとも) ¤  累累積和を効率率率よく処理理できるデータ構造! ¤  以下のことがそれぞれO(logN)で可能 ¤  a[1]〜~a[k] までの累累積和を求める ¤  a[k] の値を更更新する ¤  ⇒ 今回の⽤用途にピッタリ! ¤  addクエリ ¤  ブロックの総数を覚えておいて、末尾位置に更更新クエリ ¤  challengeクエリ ¤  累累積和クエリを使って⼆二分探索索し、位置を求める ¤  “go” なら、⾒見見つけた位置のブロックに更更新クエリ
  • 12.
    ⼀一番上のブロックを叩く時 ¤  上部に処理理後ブロック(サイズが0)が溜溜まると誤判定の可能性が! ¤  ⼀一番上かどうかの判定 ¤  シミュレーション中、 だるまの⾼高さを持っておく(Hとおく) ¤  ハンマーの下⾯面位置に当たる ブロックの最下部位置を  X とする サイズ0 = 処理理後 ¤  X + (ブロックの⾼高さ) = H なら⼀一番上! ⼀一番上
  • 13.
    解法 ¤  クエリを先読みして、登場するブロック数をカウント ¤  そのサイズでFenwickTreeを初期化 ¤  クエリが来るたびに、以下の処理理をする ¤  addクエリ ¤  現在の末尾位置にブロックのサイズで更更新クエリ ¤  challengeクエリ ¤  累累積和クエリを使って⼆二分探索索し、位置を求める ¤  “go” なら、⾒見見つけた位置のブロックに更更新クエリ
  • 14.
    統計 ¤  First AC: hos.lyric* (56:09) ¤  正解数 : 31 ¤  通した⼈人(31/205) : 15% ¤  ACだった解答(31/281) : 11%