Senの競技プログラミング備忘録

こけた問題を自分用の解説で載せる。けんちょんさんのブログを目指したい。質的にも量的にも。こけた問題だけに限定するけど

2018-2019 ICPC, NEERC, Southern Subregional Contest (Online Mirror, ACM-ICPC Rules, Teams Preferred) - B. Berkomnadzor

codeforces.com

概要

32bitのIPアドレスがN個与えられる。それぞれのアドレスには、悪いと良いがある。悪いアドレスは必ずブロックし、よいアドレスは必ず通す。何もないアドレスは、通すことにする。
ところで、サブネットというのを定める。192.168.0.1/8の下から8bit分以外一致してるのを、192.168.0.1/8のサブネットという。

このルールで、あるアドレスがよいアドレスでもあり、わるいアドレスでもある場合は、-1と出力せよ。そうでないのなら、このサブネットという構造を使って、ブロックするべきアドレスの数を最小化せよ。

制約: 1 <= N <= 2 * 10^5

ACするまで

1. 人のソースコードを見る。
2. 心を理解する。
3. 半分写経、半分自分で書く。 AC!(実装力だー!)

考察

この問題では、ひとまず次のように言い換える。

1. いくつかのよい区間と悪い区間が与えられる。
2. よい区間と悪い区間が交わることがあるのかをチェック
3. いい感じに、代表的なサブネットをみつける。

よい区間と悪い区間の交わりのチェックだが、ACソースコードのように、ソートしてしゃくとり法の要領でやるときれいに、しかも計算量がひとめでわかりやすい。

ここで、代表的なサブネットを見つけるにあたって、次のように考える。

サブネットのサイズをどんどん半分にしておいて、ちょうど含まれるようなサイズが初めて現れたのならば、それが代表的なサブネットとして答えとなる。

今回はとりわけ、IPアドレス自体も2のべき乗と相性がいいので、分割統治法でうまくいく。

分割統治の関数内で、
今見てるものの左端と右端(そしてその区間の長さ)、その左端と右端の間にある区間の一覧
を受け取って、

  • すべてよいアドレスor悪いアドレスのならば、サブネットで完全に被覆できる。
  • そうでないのならば、今の左端と右端の真ん中でまた(左端, 真ん中)と(真ん中, 右端)のように区間を分割する。

この際、分ける際で真ん中をまたぐような区間については、サブネットを設定するにあたって、他との整合性を考えるとどう考えても1つのサブネットにすることはできないので、左右2つに分割する(詳細はソースコード参照)

ACソースコード
Submission #67411974 - Codeforces

一言

分割統治法って言葉で説明するの難しいなぁ。まあ実装力がついたってことで

Special Thanks

2018-2019 ICPC, NEERC, Southern Subregional Contest (Online Mirror) Solution - 阿波罗2003 - 博客园

Codeforces紫色,实力果然非凡!非常感谢你的代码与解释!