Official

G - Worst Picture Editorial by kyopro_friends


答えが \(N\) となるケースを除き、点 \(p\)\(2\) 人の人を結ぶような\(O(N^2)\) 本の直線上にあります。そのような直線のうち、\(x<0\) の領域を通過するようなもの全体の集合を \(S\) とします。

\(|S|=0\) のとき(すなわち、全ての \(X_i\) の値が等しいとき) 答えは \(N\) です。

\(|S|>0\) のとき、\(p\) の候補として考えるべきは \(S\) に属する各直線上の点です。\(p\)\(S\) に属する \(1\) つの直線の上に存在する場合については、直線を決めるごとに \(O(N)\) で写らない人数を求めることができるため \(O(N^3)\) で調べることができます。\(p\)\(S\) に属する複数の直線上に存在する場合については、直線の交点のみを考慮すれば十分です。最悪の場合 \(|S|=\Theta(N^2)\) であることから候補となる点は \(\Theta(N^4)\) 個あり、それぞれから各人が隠れるかどうかを愚直に調べると \(\Theta(N^6)\) などとなります。この解法でも高速な言語で適切な実装をすると実行時間制限に余裕を持って間に合わせることができますが、より高速な方法を考えます。

\(|S|\) に属する各直線に対し、その直線上に何人の人がいるかを \(O(N^3)\) で予め計算しておきます。
その後、点の座標をキーに、その点を通る直線の集合を値に持つ連想配列を用意し、\(|S|\) に属する \(2\) 直線の交点を \(O(N^4)\) かけて求めながらこの連想配列を更新することで、全体で \(O(N^4 \log N)\) で答えを求めることができます。

\(3\) 次元空間での直線の交点を求めるには、\(2\) 直線を平面 \(z=0\) に射影して \(xy\) - 平面における交点を求め、その点における \(z\) 座標を求めればよいです。ただし、\(z=0\) に射影した結果、\(2\) 直線が重なるケースについては適切に扱う必要があります(簡単な解決策は、\(y=0\)\(x=0\) など別の平面へ射影して考えることです)。

誤差の影響を避けるため、座標は有理数で計算するのがよいでしょう。入力される点の座標が十分小さいことから、約分を行わないことでより高速に動作します。(適切な計算方法では、計算過程に現れる値は座標の値の4乗程度になります)

Writer解(C++) 約分あり(1200ms)
Writer解(C++) 約分なし(50ms)
Writer解(Python)

posted:
last update: