Official

E - K-colinear Line Editorial by mechanicalpenciI


\(K=1\) のときは、\(N\) 点のうちある \(1\) 点を通る直線が条件をみたし、\(N\geq 1\) が保証されているので、そのようなものは無数に存在します。
具体的には \(N\) 点のうち \(1\) 点を取り出してその座標を \((x_0,y_0)\) とすると、任意の実数 \(a\) に対して、\(y-y_0=a(x-x_0)\) で表される直線がすべて条件をみたします。

一方、特定の相異なる \(2\) 点を通る直線はただ \(1\) つに定まる事から、\(N\) 点のうち \(2\) 点以上を通る直線は高々 \(\frac{N(N-1)}{2}\) 本しか存在しません。それぞれに対して \(N\) 点のうち何点を通るか調べればよいです。

ここで、相異なる \(2\)\(A\) \((x_0,y_0)\)\(B\) \((x_1,y_1)\) を通る直線の上に \(P\) \((x,y)\) が乗っている事は ある実数 \(k\) を用いて\(\overrightarrow{AP}=k\overrightarrow{AB}\) と書ける事と同値であり、これは \((x_1-x_0)(y-y_0)\)\((y_1-y_0)(x-x_0)\) が等しいかどうかで判定することができます。

よって、判定は \(O(1)\) で出来るため、それぞれの直線に対して何点が乗っているかは \(O(N)\) で判定できます。直線の数が \(O(N^2)\) であることから、全体で \(O(N^3)\) で求まり、十分高速にこの問題を解くことができました。同じ直線を重複して数えないように注意してください。

c++による実装例 :

#include <bits/stdc++.h>
using namespace std;

long long px[300];
long long py[300];
bool flag[300][300];

bool colinear(int a, int b, int c) {
	long long val1 = (py[b] - py[a])*(px[c] - px[a]);
	long long val2 = (px[b] - px[a])*(py[c] - py[a]);
	return (val1 == val2);
}

int main(void) {
	int n, k, cnt, ans;
	vector<int>list;

	cin >> n >> k;
	for (int i = 0; i < n; i++)cin >> px[i] >> py[i];

	if (k == 1) {
		cout << "Infinity" << endl;
		return 0;
	}

	for (int i = 0; i < n; i++)for (int j = i + 1; j < n; j++)flag[i][j] = true;
	ans = 0;

	for (int i = 0; i < n; i++) {
		for (int j = i + 1; j < n; j++) {
			if (flag[i][j]) {
				cnt = 2;
				list.clear();
				list.push_back(i);
				list.push_back(j);
				for (int ii = j + 1; ii < n; ii++) {
					if (colinear(i, j, ii)) {
						cnt++;
						list.push_back(ii);
					}
				}
				for (int ii = 0; ii < cnt; ii++)for (int jj = ii + 1; jj < cnt; jj++)flag[list[ii]][list[jj]] = false;
				if (cnt >= k)ans++;
			}
		}
	}

	cout << ans << endl;
	return 0;
}

posted:
last update: