SlideShare a Scribd company logo
1 of 88
Download to read offline
Re: 永続データ構造が分からな
    い人のためのスライド
                 @qnighy
  Competitive Programing Advent Calendar 2012
このスライドについて
• Competitive Programming Advent Calendar
  2012の12/1の担当記事です。
• Advent Calendarのサイトはこちら
経緯
経緯
経緯
経緯
経緯
経緯
• 被害者が何名か出ました




• 今日は少しだけ真面目に書きます
問題
• 三問やります
    – Crayfish Scrivener (IOI 2012, day 1)
    – L-th Number (UTPC 2011)
    – Copy and Paste (JOI Spring 2012, day 4)
• 三問における使い方の違いみたいなのに焦
  点を当てていこうかと思っています
• ネタバレあり
•   僕より詳しい人のツッコミが入る可能性に怯えています
永続データ構造
• 変更前のデータを扱えるデータ構造の総称




  D1      変更操作    D2

       普通のデータ構造
永続データ構造
• 変更前のデータを扱えるデータ構造の総称


                 D1
  D1     変更操作


                 D2
       永続データ構造
完全永続性
• 部分永続: 最新版のみを変更可能

                 D4
            D3
       D2
  D1
完全永続性
• 完全永続: 最新版のみを変更可能
            D4   D5
       D2
                 D8
  D1
            D6
       D3        D7

            D9


• ここでは完全永続データ構造のみ扱う
2つの視点
• 履歴としての永続データ構造
• 値型としての永続データ構造
履歴としての永続データ構造
• 変更履歴を遡れる、という視点で見る
 – 昔使ったデータを再利用したい、というイメージ
値型としての永続データ構造
• 永続データ構造は元の値を保存する
 – 破壊的変更を隠せる
• 値型として見なせる
 – 2つの値を演算して新しい値を作る場合も…
問題
• Crayfish Scrivener (IOI 2012, day 1)
• L-th Number (UTPC 2011)
• Copy and Paste (JOI Spring 2012, day 4)
問題
• Crayfish Scrivener (IOI 2012, day 1)
Crayfish Scrivener
• 問題文の入手先
• 概要
 – エディタの動作をシミュレーションします
 – 入力操作: 末尾に1文字足します。
 – undo操作: 直前のK個をもとに戻します
 – 入力・undoはそれぞれ1回の操作とみなします
  • つまり、undoのundoができます
 – 文字取得: 現在のi番目の文字を教えて下さい
Crayfish Scrivener
• undoのundo???
Crayfish Scrivener
                             0: (空)
• 例:
1.   Aを入力
                      1: A
Crayfish Scrivener
                              0: (空)
• 例:
1.   Aを入力
                      1: A
2.   Bを入力


                      2: AB
Crayfish Scrivener
                             0: (空)
• 例:
1.   Aを入力
                     1: A
2.   Bを入力
3.   1回分もとに戻す
                     2: AB

                                      3: A
Crayfish Scrivener
                             0: (空)
• 例:
1.   Aを入力
                     1: A
2.   Bを入力
3.   1回分もとに戻す
4.   Cを入力            2: AB

                                      3: A



                                             4: AC
Crayfish Scrivener
                              0: (空)
• 例:
1.   Aを入力
                     1: A
2.   Bを入力
3.   1回分もとに戻す
4.   Cを入力            2: AB
5.   2回分もとに戻す
                                       3: A



                                              4: AC
                      5: AB
Crayfish Scrivener
                              0: (空)
• 例:
1.   Aを入力
                     1: A
2.   Bを入力
3.   1回分もとに戻す
4.   Cを入力            2: AB
5.   2回分もとに戻す
6.   Dを入力                              3: A



                                              4: AC
                      5: AB

                                        6: ABD
Crayfish Scrivener
                              0: (空)
• 例:
1.   Aを入力
                     1: A
2.   Bを入力
3.   1回分もとに戻す
4.   Cを入力            2: AB
5.   2回分もとに戻す
6.   Dを入力                              3: A

• これを”作業履歴
  ツリー”と呼ぶ             5: AB
                                              4: AC

  ことにする
                                        6: ABD
Crayfish Scrivener
• undoのundo???
• →冷静に考えれば、単純にK個前の時の文字
  列をコピーしてくればよいことがわかります。
Crayfish Scrivener
• 入力操作(文字c)
 1. S[t+1] ← S[t] + c
 2. t++
• undo操作(K回)
 1. S[t+1] ← S[t-K]
 2. t++
• 読み出し操作
 1. return S[t][i]
Crayfish Scrivener
• 素朴に実装すると二乗
• 文字列のコピーコストを減らしたい
Crayfish Scrivener
• 素朴に実装すると二乗
• 文字列のコピーコストを減らしたい
•  配列を永続化すれば良さそう
Crayfish Scrivener
• 素朴に実装すると二乗
• 文字列のコピーコストを減らしたい
• △ 配列を永続化すれば良さそう
Crayfish Scrivener
•   素朴に実装すると二乗
•   文字列のコピーコストを減らしたい
•   △ 配列を永続化すれば良さそう
•   ○ リストを永続化しよう!!
リスト = 永続stack
• リストへの追加: new Node(a, item)
• リストからの削除: a->next
• 先頭アイテムの取得: a->item
Crayfish Scrivener
                                   空
                                       [0]
• 例:
1.   Aを入力
                         A   [1]
Crayfish Scrivener
                                        空
                                            [0]
• 例:
1.   Aを入力
2.   Bを入力                   A     [1]




                        B       [2]
Crayfish Scrivener
                                     空
                                           [0]
• 例:
1.   Aを入力
2.   Bを入力                  A     [1] [3]
3.   1回分もとに戻す



                       B       [2]
Crayfish Scrivener
                                     空
                                           [0]
• 例:
1.   Aを入力
2.   Bを入力                  A     [1] [3]
3.   1回分もとに戻す
4.   Cを入力


                       B       [2]         C     [4]
Crayfish Scrivener
                                         空
                                             [0]
• 例:
1.   Aを入力
2.   Bを入力                  A     [1] [3]
3.   1回分もとに戻す
4.   Cを入力
5.   2回分もとに戻す
                       B       [2] [5]       C     [4]
Crayfish Scrivener
                                         空
                                             [0]
• 例:
1.   Aを入力
2.   Bを入力                  A       [1] [3]
3.   1回分もとに戻す
4.   Cを入力
5.   2回分もとに戻す
6.   Dを入力              B                     C
                               [2] [5]             [4]




                               D     [6]
Crayfish Scrivener
• 永続リストを使って簡潔に表現できた!
• でもi番目の文字はどうやって見つけるの
  か?

• 次のページに答えを書きます。
Crayfish Scrivener
• 永続リストを使って簡潔に表現できた!
• でもi番目の文字はどうやって見つけるの
  か?
• 答え:
 – 普通のリストでは1文字前のリンクのみ保持して
   いる。
 – 2^x文字前のリンクを全て持てば良い。
Crayfish Scrivener
                                    空
                                        [0]
• 例に戻ってみる

                      A       [1] [3]




                  B       [2] [5]       C     [4]




                          D     [6]
Crayfish Scrivener
                             空
• 例に戻ってみる
• 各時点でのデータは
                     A
  リストだった

                 B




                         D
Crayfish Scrivener
                      空
• 例に戻ってみる
• 各時点でのデータは
                  A
  リストだった

                          C
Crayfish Scrivener
                                   空
                                       [0]
• 例に戻ってみる
• 各時点でのデータは
                     A
  リストだった                     [1] [3]

• 全体を俯瞰すると
  逆向きの木になっている    B                     C
                         [2] [5]             [4]
  ことがわかる

                         D     [6]
Crayfish Scrivener
                        空
                             [0]
• 例に戻ってみる
• 各時点でのデータは
                A [1] [3]
  リストだった
• 全体を俯瞰すると
  逆向きの木になっている B              C
                 [2] [5]           [4]
  ことがわかる
• これを「通時的構造」とでも
  呼ぶことにしよう       D [6]
Crayfish Scrivener (一般化)
• 一般にi文字目を書き換えるよう一般化した問
  題を考える
• →永続配列を実装する必要がある

• Wikipediaの「永続データ構造」の記事には永続配列としてVListが紹介さ
  れているが、これは書き込みがランダムアクセスではないために配列と
  は呼べない。また、完全永続的でないので今回の問題には適さない。
永続配列
• 配列: map<int,T>として見なせる
• 永続な平衡二分木を作れば良さそう
永続配列
• 配列: map<int,T>として見なせる
• 永続な平衡二分木を作れば良さそう

• ただし、一般的な永続平衡二分木を実装する
  必要はない
 – キーであるintのもつ性質を活用する
 – これについては次のセクションで解説
問題
• Crayfish Scrivener (IOI 2012, day 1)
• L-th Number (UTPC 2011)
• Copy and Paste (JOI Spring 2012, day 4)
問題

• L-th Number (UTPC 2011)
L-th Number
• 問題文の入手先
• 概要
 – 無向木があります。頂点に数字が書かれていま
   す。
 – クエリ(v,w,L)が順番に与えられます。
 – 頂点vと頂点wを結ぶ経路上の数字のうち、L番目
   に小さいものを答えて下さい。
L-th Number
• 解説PDFがあるので、ちゃんと解説を知りたい
  人はそっちを読んでください。

• 一応、次のページで軽く解説します。
L-th Number
• 無向木に根を与えて有向木にします。
• 頂点vから根までの経路上での数字の分布を
  木構造で管理します。(総和を計算するRMQ
  を作ります。)
• 頂点vとwの間での分布は、その差分で得ら
  れます。
• 二分探索で答えが出ます。
L-th Number
• 無向木に根を与えて有向木にします。
• 頂点vから根までの経路上での数字の分布を
  木構造で管理します。(総和を計算するRMQ
  を作ります。)
• 頂点vとwの間での分布は、その差分で得ら
  れます。
• 二分探索で答えが出ます。
L-th Number
• 「頂点vから根における分布」→「その子供w
  から根における分布」の計算
 – 分布を表すデータ構造に変更を加える
 – でも元のデータも残したい、という問題
 – →「履歴としての永続データ構造」と見なせる
L-th Number
• 作業履歴ツリーは例えば以下のようになる
• (公式解説スライドの例と同じもの)
  空           2


              2,5


      2,4,5              2,5,8


               2,5,8,9           2,5,7,8
L-th Number
• 永続リストの通時的構造は木だった
• 永続木の通時的構造は?
L-th Number
• 先ほどの例を使ってやってみよう
• (平衡のさせかたは適当)
  空           2


              2,5


      2,4,5              2,5,8


               2,5,8,9           2,5,7,8
L-th Number
• 頂点1


  空             2


                2,5


        2,4,5              2,5,8
                                             2
                 2,5,8,9           2,5,7,8
L-th Number
• 頂点3


  空             2


                2,5
                                                 5
        2,4,5              2,5,8
                                             2
                 2,5,8,9           2,5,7,8
L-th Number
• 頂点2


  空             2


                2,5
                                                 4
        2,4,5              2,5,8
                                             2       5
                 2,5,8,9           2,5,7,8
L-th Number
• 頂点4


  空             2                                    8


                2,5
                                                 5
        2,4,5              2,5,8
                                             2
                 2,5,8,9           2,5,7,8
L-th Number
• 頂点5


  空             2                                    8

                                                         9
                2,5
                                                 5
        2,4,5              2,5,8
                                             2
                 2,5,8,9           2,5,7,8
L-th Number
• 頂点6                                                    8




  空             2                                    7


                2,5
                                                 5
        2,4,5              2,5,8
                                             2
                 2,5,8,9           2,5,7,8
L-th Number
• 通時的構造                                                    8




  空           2                                    7       8       8

                                                                       9
              2,5
                                               5       4
      2,4,5              2,5,8
                                           2                   5
               2,5,8,9           2,5,7,8
L-th Number
• DAGになっていることが
  おわかり頂けただろうか

• (この例だと特殊なのでわかりにくいが…)
実装上のテクニック
• 実装上のテクニック
 – Crayfish Scrivenerと併せて
• キーがintであることなどに注目すると、赤黒
  とかは必要ないことがわかる。
 – 木の形状は固定でよい
 – データは葉にのみ持たせたほうが楽ちん
   • ただし、L-th NumberはそもそもSegment Treeなので、
     生データを葉にのみ持たせるのは割と当然
実装上のテクニック
• L-th Numberの場合
• 「存在する数字の集合」ではなく、「ある範囲
  内に収まる数字はいくつあるか」で持っておく
• 木の形状を固定にすると良い点
 – 実装が簡単
 – オーダーが落ちる(二分探索との併用なので、計
   算しつつ探索を下ることができれば速くなる)
実装上のテクニック
• 参考問題
 – Apples (JOI Spring 2011 day4)
    • 実は木の形状を固定できる例
    • 遅延評価でメモリを節約する工夫が必要
 – Bug Party (JOI Final 2011)
    • 二分探索とツリー処理の合併で高速化できる例
ここまでの地図
• 履歴としての永続データ構造
 – 作業履歴が定義できて、それが木構造をなす
 – リストの例: Crayfish Scrivener
   • 通時的構造が木になることがわかった
 – 木構造の例: L-th Number
   • 通時的構造がある種のDAGになることがわかった
• 値型としての永続データ構造
 – ??
問題
• Crayfish Scrivener (IOI 2012, day 1)
• L-th Number (UTPC 2011)
• Copy and Paste (JOI Spring 2012, day 4)
問題


• Copy and Paste (JOI Spring 2012, day 4)
Copy and Paste
• 問題文の入手先
• 概要
 – エディタの動作をシミュレーションします
 – 初期入力: 初期文字列Sが与えられます。
 – コピペ: ある範囲をある位置にコピー・挿入しま
   す
 – 溢れ: M文字より溢れたらトリミングします
 – 最終結果を出力してください
Copy and Paste
• これも、よくわかる解説スライドがあるので、
  もういいんじゃないかと思いますが………

• 一応、今回のテーマに関係する部分を適当
  に解説します
Copy and Paste
• 見た感じでヤバい問題
 –   これを見た感じでヤバいって思えないと大きな失態を演じることになるから気をつけた方がいい



• なんかこう、副作用を気にしないで好きなよう
  に切り貼りできる便利なのが欲しいよね
Copy and Paste
• 副作用を気にしないで?
 – 永続データ構造?
• 切ったり貼ったり出来る?
 – 平衡二分探索木?
• !!永続な平衡二分探索木を組もう!!
永続やるときの制約
• ならし解析はだいたい無理
 – 完全永続的なデータ構造では、同じ状態遷移を
   何回も繰り返せるので、ならし解析が壊れる
• 乱択アルゴリズムも難しいらしい
 – こっちはよくわからないけどとにかく難しいらしい
Copy and Paste
• !!赤黒木を書こう!!
Copy and Paste
• 実装上のテクニックは公式解説にあるので省
  略
 –   実は自分で実装してみていないから迂闊なこと言えないんだ、なんて言えない…
Copy and Paste
• この問題では、次のような操作があることに
  注意
 – 文字列の連結(c := a + b)
• 今までの例では、1つのデータを少しだけ加
  工して新しいデータを作っていた
• ここでは、2つのデータを併せて何かをする操
  作が出てくる
• =値型としての永続データ構造
Copy and Paste
• 「値型としての永続データ構造」の性質
 – 通時的構造はDAGになるが、先程のものとは違う
   性質を持っている
 – それは、「頂点vからwへの遷移方法が2通り以上
   ある可能性がある」ということ
 – そういう性質などもあって、こういう永続データ構
   造は扱いがめんどいようです。
Copy and Paste
• 本当はこれの実装上のテクニックとかも書く
  予定でしたが、もう眠いので止めます。
• ゴミ回収の必要とかがあるんですが、C++使
  いの人はshared_ptrがあるから
 – はやく競プロでBoostが使えるようになるといいで
   すね………………
突飛なまとめ
• 永続データ構造と一口にいってもその条件は何段階
  かある
 – 特に、insert/delete系の操作しか行わない場合と、merge
   が必要な場面では実装の要求レベルがだいぶ変わってく
   る
• 永続データ構造を、通時的観点から俯瞰すると新たな
  視点が得られる(かも)
• つまり、「代数的データ型でデータ構造を構築する」と
  いう観点から永続データ構造を理解することも重要だ
  が、結局は競技プログラミングにおける手法の一つと
  して使うのだから、手続き型的な観点から解体して、
  必要なテクニックだけ取り出せるようにすると良いよね
参考
•   著名データ構造の永続的な実装の例
•   配列 : 二分木による実装
•   スタック : リストと等価
•   ヒープ : Leftist Heapの永続的実装
    – Binomial Heapの永続的実装もある
• キュー : Finger Tree, Implicit Queue
• マップ : 赤黒木系統、AVL系統
• DSU(Union Find) : Sylvain Conchon and Jean-
  Christophe Filliâtreによる論文
参考文献
• Chris Okasaki, 1999, Purely Functional Data Structures, Cambridge
  University Press, 232 Pages.
• Sylvain Conchon and Jean-Christophe Filliâtre, 2007, A persistent
  union-find data structure, ML ‘07 Proceedings of the 2007
  workshop on ML, Pages 37-46, ACM.
• VList – Wikipedia, the free encyclopedia (2012/12/02閲覧)
• 素集合データ構造 – Wikipedia (2012/12/02閲覧)
• 永続データ構造 – Wikipedia (2012/12/02閲覧)
• 2-3 フィンガーツリー – Wikipedia (2012/12/02閲覧)
• Tasks | IOI 2012 (2012/12/02閲覧)
• 東京大学プログラミングコンテスト2011 (2012/12/02閲覧)
• 問題一覧 – 情報オリンピック 問題と解説 (2012/12/02閲覧)
fin
• ご清聴ありがとうございました

More Related Content

What's hot

図と実装で理解する『木構造入門』
図と実装で理解する『木構造入門』図と実装で理解する『木構造入門』
図と実装で理解する『木構造入門』Proktmr
 
指数時間アルゴリズム入門
指数時間アルゴリズム入門指数時間アルゴリズム入門
指数時間アルゴリズム入門Yoichi Iwata
 
競技プログラミングにおけるコードの書き方とその利便性
競技プログラミングにおけるコードの書き方とその利便性競技プログラミングにおけるコードの書き方とその利便性
競技プログラミングにおけるコードの書き方とその利便性Hibiki Yamashiro
 
Rolling Hashを殺す話
Rolling Hashを殺す話Rolling Hashを殺す話
Rolling Hashを殺す話Nagisa Eto
 
勉強か?趣味か?人生か?―プログラミングコンテストとは
勉強か?趣味か?人生か?―プログラミングコンテストとは勉強か?趣味か?人生か?―プログラミングコンテストとは
勉強か?趣味か?人生か?―プログラミングコンテストとはTakuya Akiba
 
充足可能性問題のいろいろ
充足可能性問題のいろいろ充足可能性問題のいろいろ
充足可能性問題のいろいろHiroshi Yamashita
 
最小カットを使って「燃やす埋める問題」を解く
最小カットを使って「燃やす埋める問題」を解く最小カットを使って「燃やす埋める問題」を解く
最小カットを使って「燃やす埋める問題」を解くshindannin
 
AtCoder Beginner Contest 021 解説
AtCoder Beginner Contest 021 解説AtCoder Beginner Contest 021 解説
AtCoder Beginner Contest 021 解説AtCoder Inc.
 
様々な全域木問題
様々な全域木問題様々な全域木問題
様々な全域木問題tmaehara
 
AtCoder Beginner Contest 007 解説
AtCoder Beginner Contest 007 解説AtCoder Beginner Contest 007 解説
AtCoder Beginner Contest 007 解説AtCoder Inc.
 
AtCoder Beginner Contest 015 解説
AtCoder Beginner Contest 015 解説AtCoder Beginner Contest 015 解説
AtCoder Beginner Contest 015 解説AtCoder Inc.
 

What's hot (20)

Rolling hash
Rolling hashRolling hash
Rolling hash
 
Binary indexed tree
Binary indexed treeBinary indexed tree
Binary indexed tree
 
図と実装で理解する『木構造入門』
図と実装で理解する『木構造入門』図と実装で理解する『木構造入門』
図と実装で理解する『木構造入門』
 
指数時間アルゴリズム入門
指数時間アルゴリズム入門指数時間アルゴリズム入門
指数時間アルゴリズム入門
 
競技プログラミングにおけるコードの書き方とその利便性
競技プログラミングにおけるコードの書き方とその利便性競技プログラミングにおけるコードの書き方とその利便性
競技プログラミングにおけるコードの書き方とその利便性
 
明日使えないすごいビット演算
明日使えないすごいビット演算明日使えないすごいビット演算
明日使えないすごいビット演算
 
Rolling Hashを殺す話
Rolling Hashを殺す話Rolling Hashを殺す話
Rolling Hashを殺す話
 
双対性
双対性双対性
双対性
 
勉強か?趣味か?人生か?―プログラミングコンテストとは
勉強か?趣味か?人生か?―プログラミングコンテストとは勉強か?趣味か?人生か?―プログラミングコンテストとは
勉強か?趣味か?人生か?―プログラミングコンテストとは
 
Convex Hull Trick
Convex Hull TrickConvex Hull Trick
Convex Hull Trick
 
充足可能性問題のいろいろ
充足可能性問題のいろいろ充足可能性問題のいろいろ
充足可能性問題のいろいろ
 
最小カットを使って「燃やす埋める問題」を解く
最小カットを使って「燃やす埋める問題」を解く最小カットを使って「燃やす埋める問題」を解く
最小カットを使って「燃やす埋める問題」を解く
 
abc032
abc032abc032
abc032
 
直交領域探索
直交領域探索直交領域探索
直交領域探索
 
動的計画法を極める!
動的計画法を極める!動的計画法を極める!
動的計画法を極める!
 
AtCoder Beginner Contest 021 解説
AtCoder Beginner Contest 021 解説AtCoder Beginner Contest 021 解説
AtCoder Beginner Contest 021 解説
 
様々な全域木問題
様々な全域木問題様々な全域木問題
様々な全域木問題
 
AtCoder Beginner Contest 007 解説
AtCoder Beginner Contest 007 解説AtCoder Beginner Contest 007 解説
AtCoder Beginner Contest 007 解説
 
AtCoder Beginner Contest 015 解説
AtCoder Beginner Contest 015 解説AtCoder Beginner Contest 015 解説
AtCoder Beginner Contest 015 解説
 
RMQ クエリ処理
RMQ クエリ処理RMQ クエリ処理
RMQ クエリ処理
 

More from Masaki Hara

You won't know it's now Rust
You won't know it's now RustYou won't know it's now Rust
You won't know it's now RustMasaki Hara
 
How I Contribute to Rust Compiler
How I Contribute to Rust CompilerHow I Contribute to Rust Compiler
How I Contribute to Rust CompilerMasaki Hara
 
ご静聴ありがとうございました
ご静聴ありがとうございましたご静聴ありがとうございました
ご静聴ありがとうございましたMasaki Hara
 
いろいろな問題の解説
いろいろな問題の解説いろいろな問題の解説
いろいろな問題の解説Masaki Hara
 
“A ::= aAa / a” in PEG
“A ::= aAa / a” in PEG“A ::= aAa / a” in PEG
“A ::= aAa / a” in PEGMasaki Hara
 
Spaceships 解説
Spaceships 解説Spaceships 解説
Spaceships 解説Masaki Hara
 
Proving Decidability of Intuitionistic Propositional Calculus on Coq
Proving Decidability of Intuitionistic Propositional Calculus on CoqProving Decidability of Intuitionistic Propositional Calculus on Coq
Proving Decidability of Intuitionistic Propositional Calculus on CoqMasaki Hara
 
永続データ構造が分からない人のためのスライド
永続データ構造が分からない人のためのスライド永続データ構造が分からない人のためのスライド
永続データ構造が分からない人のためのスライドMasaki Hara
 
書くネタがCoqしかない
書くネタがCoqしかない書くネタがCoqしかない
書くネタがCoqしかないMasaki Hara
 
joi2012-sp-day2-broadcasting
joi2012-sp-day2-broadcastingjoi2012-sp-day2-broadcasting
joi2012-sp-day2-broadcastingMasaki Hara
 

More from Masaki Hara (13)

You won't know it's now Rust
You won't know it's now RustYou won't know it's now Rust
You won't know it's now Rust
 
How I Contribute to Rust Compiler
How I Contribute to Rust CompilerHow I Contribute to Rust Compiler
How I Contribute to Rust Compiler
 
Coqの公理
Coqの公理Coqの公理
Coqの公理
 
ご静聴ありがとうございました
ご静聴ありがとうございましたご静聴ありがとうございました
ご静聴ありがとうございました
 
いろいろな問題の解説
いろいろな問題の解説いろいろな問題の解説
いろいろな問題の解説
 
“A ::= aAa / a” in PEG
“A ::= aAa / a” in PEG“A ::= aAa / a” in PEG
“A ::= aAa / a” in PEG
 
Spaceships 解説
Spaceships 解説Spaceships 解説
Spaceships 解説
 
Proving Decidability of Intuitionistic Propositional Calculus on Coq
Proving Decidability of Intuitionistic Propositional Calculus on CoqProving Decidability of Intuitionistic Propositional Calculus on Coq
Proving Decidability of Intuitionistic Propositional Calculus on Coq
 
永続データ構造が分からない人のためのスライド
永続データ構造が分からない人のためのスライド永続データ構造が分からない人のためのスライド
永続データ構造が分からない人のためのスライド
 
Coqでsprintf
CoqでsprintfCoqでsprintf
Coqでsprintf
 
Coqでsprintf
CoqでsprintfCoqでsprintf
Coqでsprintf
 
書くネタがCoqしかない
書くネタがCoqしかない書くネタがCoqしかない
書くネタがCoqしかない
 
joi2012-sp-day2-broadcasting
joi2012-sp-day2-broadcastingjoi2012-sp-day2-broadcasting
joi2012-sp-day2-broadcasting
 

Re永続データ構造が分からない人のためのスライド