考え方
$K=1$ならInfinity
なので,その他の場合を考える.2点を決めれば傾きが決まる.このとき,何点通るかをカウントする.「$x$個の点が一直線上に乗っているとき,この直線はxx回カウントされる」という考え方ができる.
※これに気付かずに,setをつかって区別してしまった...
Editorial - UNIQUE VISION Programming Contest 2022(AtCoder Beginner Contest 248)
傾きが同じかどうかは,
\begin{aligned}
&\frac{\Delta Y_{1}}{\Delta X_{1}}
=\frac{\Delta Y_{2}}{\Delta X_{2}} \\
&\Leftrightarrow
\Delta X_{1}\Delta Y_{2} = \Delta Y_{1} \Delta X_{2}
\end{aligned}
で考えると,整数のまま扱える.&\frac{\Delta Y_{1}}{\Delta X_{1}}
=\frac{\Delta Y_{2}}{\Delta X_{2}} \\
&\Leftrightarrow
\Delta X_{1}\Delta Y_{2} = \Delta Y_{1} \Delta X_{2}
\end{aligned}
回答例
setを使った回答.N, K = map(int, input().split()) P = [list(map(int, input().split())) for _ in range(N)] if K == 1: exit(print('Infinity')) ans = 0 seen = set() for i in range(N): for j in range(i + 1, N): cnt = 0 points = [] x1 = P[j][0] - P[i][0] y1 = P[j][1] - P[i][1] for k in range(N): x2 = P[k][0] - P[i][0] y2 = P[k][1] - P[i][1] if x1 * y2 == y1 * x2: points.append(k) cnt += 1 points = tuple(sorted(points)) if cnt >= K and not points in seen: ans += 1 seen.add(points) print(ans)
このように$i < j$の組み合わせで考えると,$x$個の点を通る直線はちょうど
\begin{aligned}
\binom{x}{2}
=\frac{x (x -1)}{2}
\end{aligned}
回カウントされるから,setなしでも実装できる:
\binom{x}{2}
=\frac{x (x -1)}{2}
\end{aligned}
N, K = map(int, input().split()) P = [list(map(int, input().split())) for _ in range(N)] if K == 1: exit(print('Infinity')) cnt = [0] * (N + 1) for i in range(N): for j in range(i + 1, N): tmp = 0 x1 = P[j][0] - P[i][0] y1 = P[j][1] - P[i][1] for k in range(N): x2 = P[k][0] - P[i][0] y2 = P[k][1] - P[i][1] if x1 * y2 == y1 * x2: tmp += 1 cnt[tmp] += 1 print(sum(2 * cnt[i] // (i * (i - 1)) for i in range(K, N + 1)))