競プロ過去問演習#1 - No Need

published: ,
last modified: .

lang: ja

category: competitive_programming

tags: atcoder ocaml

No Need

よい集合全体を列挙することは到底できないから,その必要がない形に言い換えたい. よい集合全体をGG, 必要なカードの集合をNeedNeedとする.以下カードiiを書かれている値a[i]a[i]と同一視する.

部分点解法(editorial+α)

問題文より:

iNeed    isG s.t. s{i}G\newcommand\st{\text{ s.t. }} i \notin Need \iff i \in \forall s \in G \text{ s.t. } s \setminus \{i\} \in G

である.先の要請から\forallを消すために対偶を取ると:

iNeed    isG s.t. s{i}G.i \in Need \iff i \in \exists s \in G \text{ s.t. } s \setminus \{i\} \notin G.

ところでsGs \in GとはsK\sum s \ge Kのことであった.このようにカードの数に関する形に言い換えてみると:

iNeed    is,sK s.t. si<Ki \in Need \iff i \in \exists s, \sum s \ge K \text{ s.t. } \sum s - i \lt K

すなわちKs<K+iK \le \sum s \lt K + iかつiiを含む集合ssが存在すればiiが必要であることが分かる.

このような集合ssが存在するか知りたい.「総和が範囲内であるような集合が存在するか」はdp[v]=(dp[v] = (総和がvvの集合が存在するか))のようなdp配列を更新する過程で求まる.すなわち行うdpは初期値dp[i]=truedp[i] = \text{true},状態O(K)O(K)K+i\because K+i以上は考えなくてよい),遷移O(N)O(N)i\because i枚目以外の任意のカードjjに対し,dp配列の値がある箇所dp[v]dp[v]についてdp[v+j]truedp[v+j] \gets \text{true}とする)となる.これをすべてのiiに対して繰り返すから,計算量はO(N2K)O(N^2 K)となって部分点解法が得られる.

このdpができることはeditorialを見るまで気付けなかったのだが,集合(の構成過程)を状態と見れば,総和が等しい状態を纏めて考えることができる,というような考え方でよいのだろうか.

追記(2019/03/09): DPの資料を漁っていたら部分和問題と言うものが載っていた.これは総和がある値であるかの判定問題だが,今回のように範囲内か否かも同様のDPで可能.ちなみにKKが大きかったら半分全列挙をすればO(2N/2)O(2^{N/2})らしい

満点解法: 二分探索(editorial)

カードiji \le jについてiiが必要ならばjjも必要であることを示す:再掲するが,

iNeed    is  s.t. Ks<K+ii \in Need \iff i \in \exists s \ \text{ s.t. } K \le \sum s \lt K + i

であった.いまiiが必要とするとこのようなssが存在するはずである.ssの候補は(1)jjを含むか(2)jjを含まないかに二分される. (1)の場合s<K+i\sum s \lt K + iからsjsi<K\sum s - j \le \sum s - i \lt K.よってKs<K+jK \le \sum s \lt K + jであるからjjも必要であることが言える. (2)の場合ではssからiiを除いてjjを加えた集合ttを考えてみると,KKi+jsi+j<K+jK \le K - i + j \le \sum s - i + j \lt K + jであるからttKt<K+jK \le \sum t \lt K+jを満たす(\because t=si+j\sum t = \sum s - i + j).従ってjjを必要たらしめる集合ttが構成できるからjjも必要.

よって必要である最小のカードを見付ければ,それ以上のカードはすべて必要であり,それ未満のカードはすべて不要となる(対偶).従って単調性から二分探索が可能. 解答例

嘘解法と別解

数か月前に解こうと思ったときに参照したところ嘘解法(テストケースの不足から提出すればACとなるが,実際には誤りである解法という意味の競プロ用語)だった記事があり,そこから正解法にできないかと考えた記録.

嘘解法の概略:書いてある数字の大きいほうからカードを読んで和uuを記録する.uKu \ge Kになればuuを構成する数は必要最小限でよい集合を為すから,それ以外の数はそこまでの過程では不要になる.よってそこの番地ansansを記録しておけば,最終的にansansから右がすべて不要な数と分かる.u<Ku \lt Kであればuuにカードの数を加算する.

これはすなわち「その構成要素だけでは良い集合たりえないが,加えるa[i]a[i]によっては良い集合になるような候補」のうち最適,すなわちKKとの差が最も小さいものをuuが表せているという信念に基づいている.

ところが例えばK=26, a={18,10,9,7}を考える.3番目まで見たときu=a[1]=18u=a[1]=18であるが,このとき実際に最もKKに近い候補は集合V={a[2],a[3]}={10,9}V=\{a[2],a[3]\}=\{10,9\}の総和1919であってuuではない.ここでa[4]a[4]を採用するとき,元のuuだとu+7=25<Ku+7=25 \lt Kとなり77は不必要なカードとなってしまう一方,VVの場合では集合{a[2],a[3],a[4]}={10,9,7}\{a[2],a[3],a[4]\}=\{10,9,7\}の総和は19+7=26=K19+7=26=Kとなり正しく77が必要なカードと判定される.このような理由からこれは誤った解法である.

さて実際にuuとして持っておきたいのは,KKとの差が最も小さい候補であった.反例で見たように逆転が起こるから実際にこれだけを持つことは無理そう.よって先の部分点解にあるdp配列(=すべての候補)を更新することになるが,これでも各iiに相当する処理が不要なのでO(NK)O(NK)で済む. 解答例

解法の正当性を言いたい.以下wwとしたときはdp[w]=truedp[w]=trueである,すなわちw<Kw \lt Kが総和となる数の集合SwS _wが存在するものに限るとする. いま新たにカードvvを考える.あるwwに対してw+vKw+v \ge Kとなる場合,カードを降順に見ていったことから,Sw+vS _{w+v}Sw+vS _ {w+v}自体は複数あり得るがそのうちvvを含むものとする)は「必要最小限なよい集合」,すなわちこれに含まれるどの数字を除いてもよい集合ではなくなる(\because 降順よりiSw\forall i \in S_wについてviv \le iであり,またvvの必要性からKSw+v<K+vK \le \sum S _ {w+v} \lt K + vであるから,Sw+vi<K+viK\sum S _ {w+v} - i \lt K + v - i \le K.ゆえに集合S:=Sw+v{i}S' := S _ {w+v} \setminus \{i\}S<K\sum S' \lt Kであるからよい集合に属さない).したがってSw+vS _ {w+v}に含まれるすべてのカードは必要である.一方でwwが存在しない場合はvvは(現時点では)不要である.

いまvvが必要になったとする.vvの前に不必要と判定されたカードuuがあるとき,uuは必要となるかを考えたい(満点解法の説明にもあるが現在の記法で再度説明する).ここでvvを必要たらしめたSwS_ wを考える.ここにuuが含まれていればSwS _ wの最小性からuuも必要となる.一方でそうでない場合を考えたいが,このとき降順からSw+u=Sw+uSw+vK\sum S_ {w+u} = \sum S_ w + u \ge \sum S_ w + v \ge Kであり,またSw<K\sum S _ w \lt KであったからSw+u<K+u\sum S _ {w+u} \lt K + u.これらからKSw+u<K+uK \le \sum S _ {w+u} \lt K + u,すなわちuuについてもSwS_ wで必要とできることが分かるから,これはあり得ない.

従ってvvが必要と判明したとき,それまでの全カードが必要であることが分かる.よってvvii番目のカードのときansians \gets iとし,最終的にansans番目より右側のカード,すなわちnansn-ans枚が不要とすればよい.

テストケースを様々な範囲で計5000個ほど生成して先のeditorial解と出力を比較してみたところすべて等しかったので,きっと正しい解法になったはず.

copyright © 2024 sk0

Next.js-powered!