有理数使った
問題概要
二次元平面上に 個の点がある。これらの任意のペアを結んでできり直線たちを考える (異なるペアが同一の直線を生成するときは、一つの直線とみなす)。
これらの直線たちの交点が何点生じるかを求めよ。
制約
考えたこと
有理数使った。基本的に直線たちをその傾きで分類してあげる方針で解いた。
#include <iostream> #include <sstream> #include <cstdio> #include <cstdlib> #include <cmath> #include <ctime> #include <cstring> #include <string> #include <vector> #include <stack> #include <queue> #include <deque> #include <map> #include <set> #include <bitset> #include <numeric> #include <utility> #include <iomanip> #include <algorithm> #include <functional> #include <unordered_map> using namespace std; template<class T> inline bool chmax(T& a, T b) { if (a < b) { a = b; return 1; } return 0; } template<class T> inline bool chmin(T& a, T b) { if (a > b) { a = b; return 1; } return 0; } template<class T> vector<T> make_vec(size_t a) { return vector<T>(a); } template<class T, class... Ts> auto make_vec(size_t a, Ts... ts) { return vector<decltype(make_vec<T>(ts...))>(a, make_vec<T>(ts...)); } template<class T, class V> typename enable_if<is_class<T>::value == 0>::type fill(T &t, const V &v) { t = v; } template<class T, class V> typename enable_if<is_class<T>::value != 0>::type fill(T &t, const V &v){ for (auto &e : t) fill(e, v); } #define COUT(x) cout << #x << " = " << (x) << " (L" << __LINE__ << ")" << endl template<class T1, class T2> ostream& operator << (ostream &s, pair<T1,T2> P) { return s << '<' << P.first << ", " << P.second << '>'; } template<class T> ostream& operator << (ostream &s, vector<T> P) { for (int i = 0; i < P.size(); ++i) { if (i > 0) { s << " "; } s << P[i]; } return s; } template<class T> ostream& operator << (ostream &s, vector<vector<T> > P) { for (int i = 0; i < P.size(); ++i) { s << endl << P[i]; } return s << endl; } #define EACH(i, s) for (__typeof__((s).begin()) i = (s).begin(); i != (s).end(); ++i) template<class T> ostream& operator << (ostream &s, set<T> P) { EACH(it, P) { s << "<" << *it << "> "; } return s << endl; } template<class T1, class T2> ostream& operator << (ostream &s, map<T1,T2> P) { EACH(it, P) { s << "<" << it->first << "->" << it->second << "> "; } return s << endl; } long long calc_gcd(long long a, long long b) {return b ? calc_gcd(b, a % b) : a;} struct frac { long long first, second; using D = long double; inline frac normalize() { if (second < 0) {first = -first; second = -second;} long long d = calc_gcd(abs(first), abs(second)); if (d == 0) {first = 0; second = 1;} else {first /= d; second /= d;} return *this; } frac(long long f = 0, long long s = 1) : first(f), second(s) { normalize(); } inline D to_d() const { return D(first) / second; } inline frac operator - () { (*this).first *= -1; return (*this); } inline const frac& operator = (long long a) { *this = frac(a, 1); return *this; } inline const frac& operator += (const frac& a); inline const frac& operator += (long long a); inline const frac& operator -= (const frac& a); inline const frac& operator -= (long long a); inline const frac& operator *= (const frac& a); inline const frac& operator *= (long long a); inline const frac& operator /= (const frac& a); inline const frac& operator /= (long long a); inline friend ostream& operator << (ostream& s, const frac& f) { s << f.first; if (f.second != 1) s << "/" << f.second; return s; } }; inline bool operator == (const frac &a, const frac&b) { return a.first * b.second == a.second * b.first; } inline bool operator != (const frac &a, const frac &b) { return !(a == b); } inline bool operator < (const frac& a, const frac& b) { return a.first * b.second < a.second * b.first; } inline bool operator > (const frac& a, const frac& b) { return b < a; } inline bool operator <= (const frac& a, const frac& b) { return a.first * b.second <= a.second * b.first; } inline bool operator >= (const frac& a, const frac& b) { return b <= a; } inline frac operator + (const frac& a, const frac& b) { frac res; res.first = a.first * b.second + a.second * b.first; res.second = a.second * b.second; res.normalize(); return res; } inline frac operator - (const frac& a, const frac& b) { frac res; res.first = a.first * b.second - a.second * b.first; res.second = a.second * b.second; res.normalize(); return res; } inline frac operator * (const frac& a, const frac& b) { frac res; res.first = a.first * b.first; res.second = a.second * b.second; res.normalize(); return res; } inline frac operator / (const frac& a, const frac& b) { frac res; res.first = a.first * b.second; res.second = a.second * b.first; res.normalize(); return res; } inline frac abs(const frac& a) { frac res; res = a; res.normalize(); if (res.first < 0) res.first = res.first * (-1); return res; } inline const frac& frac::operator += (const frac& x) {*this = *this + x; return *this;} inline const frac& frac::operator += (long long x) {*this = *this + x; return *this;} inline const frac& frac::operator -= (const frac& x) {*this = *this - x; return *this;} inline const frac& frac::operator -= (long long x) {*this = *this + x; return *this;} inline const frac& frac::operator *= (const frac& x) {*this = *this * x; return *this;} inline const frac& frac::operator *= (long long x) {*this = *this * x; return *this;} inline const frac& frac::operator /= (const frac& x) {*this = *this / x; return *this;} inline const frac& frac::operator /= (long long x) {*this = *this / x; return *this;} using pll = pair<long long, long long>; int N; vector<pll> ps; long long solve() { long long all = 0; vector<long long> kaburi; // y 軸に平行 map<long long, int> xs; for (int i = 0; i < N; ++i) xs[ps[i].first]++; int tmp = 0; for (auto it : xs) if (it.second > 1) ++tmp; kaburi.push_back(tmp); all += tmp; // それ以外 map<frac, set<frac> > ma; for (int i = 0; i < N; ++i) { for (int j = i+1; j < N; ++j) { if (ps[i].first == ps[j].first) continue; frac katamuki(ps[j].second-ps[i].second, ps[j].first-ps[i].first); frac seppen = ps[i].second - katamuki * ps[i].first; ma[katamuki].insert(seppen); } } for (auto it : ma) all += it.second.size(), kaburi.push_back(it.second.size()); //COUT(all); COUT(kaburi); // 集計 long long res = all * (all - 1) / 2; for (auto num : kaburi) { res -= num * (num - 1) / 2; } return res; } int main() { ios::sync_with_stdio(false); cin.tie(0); while (cin >> N) { ps.resize(N); for (int i = 0; i < N; ++i) cin >> ps[i].first >> ps[i].second; cout << solve() << endl; } }