以下、ビット列とそれが表す集合を同一視する。インデックスの集合が与えられたとき、を、インデックスの中からが大きいもの2つを残した集合とする。は結合的で可換なのでゼータ変換が適用できる。つまり、
という変換ができる。はでよい。
これでを満たすに対するの最大値が求まるが、実際にはを満たすについて考えなくてはならない。が存在してが存在してだから、を満たすに関する最大値はとして累積的に求まる。
高速ゼータ変換に関するメモ。高速ゼータ変換は各部分集合の各要素をちょうど一回ずつ重複なく処理するので、集合の合併を取る場合はそのままくっつけて良い。つまり、例えばという関数を和集合についてゼータ変換したいとするとき、つまり
を求めるとき、和集合を得る操作で重複を除く必要はない。
Common Lispに関するメモ。扱う集合が小さいので珍しくunion
を使う気になったら初歩的な失敗をした。非破壊的な合併を書いているつもりでなんとなく(sort (union list1 list2) ...)
としたのだけど、union
はリストをコピーするとは限らないのでsort
で元のリストが破壊される。(sort (nunion (copy-list list1) (copy-list2 list2)) ...)
とするか、あるいはunion
してからcopy-list
するのが正しかった。
非破壊的操作はコピーするとは限らないというポイント、わかっているつもりで普段は忘れている。(sort (mapcar ...) ...)
みたいなのも(mapcar #'identity list)
がlist
をそのまま返すような最適化は許されているので、元のリストが保たれるとは限らない。(SBCLでは大丈夫だけど。)本質的には危険なコードをけっこう書いてしまっている気がする。
SBCLに関するメモ。SBCLのmerge
はいちいちsb-kernel:specifier-type
を呼ぶので1回の呼び出しが重い。使う時には注意する必要がある。