CodeForces #256_Div2 : D. Multiplication Table
http://codeforces.com/contest/448/problem/D
問題
n * mの二次元テーブルが与えられる。
i行j列目の値はi * jと定義される。
このテーブルの内、k番目に大きい要素を答えよ。
例えば、n=2, m=3の場合テーブルは以下の図のようになり、
k=4 の時、その答えは3となる。
解法
n,mの最大値がと大きいため、
テーブルを愚直に構築し全探索を行うことはできない。
「ある数xがk番目に大きい」というのは以下のように言い換えられる
- テーブル内にx以下の数はk個以上存在する
- テーブル内にx未満の数はk個未満存在する
つまりk番目に大きい数は、ある数x以下の数がk個以上存在するような
最小のxを探せば良いことが分かる。
これはテーブル上にx以下の個数がいくつ存在するか調べる事ができれば、
二分探索で効率よく求めることができる。
では、テーブル上でどのようにx以下の個数を数える事ができるか。
これは行・列がそれぞれ単調増加している性質を利用してテーブルをジグザグ
移動しながら求めることができる。
例として4 * 5のテーブルで8以下の個数を数えたい場合、
以下のようにポインタを動かしその数は13個となる。
- 今いるマスの値が8以下
- そのマスの左側は全て8以下であることが分かるため その幅の分だけ加算し次の行へ
- 今いるマスの値が8を超える
- 8以下になるまで左側に寄せる
- 8以下になるまで左側に寄せる
ジグザクする回数は高々(n+m)回のため、全体の計算量はとなる。