E - Trapezium Editorial by en_translator
Overview of solution
First, count how many pairs of parallel edges there are. To count them, find the slope between each of \(\frac{N(N-1)}{2}\) possible pairs, and for each slope value \(x\):
- add \(\frac{c_x(c_x-1)}{2}\) to the answer, if there are \(c_x\) pairs with slope \(x\).
Here, a trapezium that is a parallelogram is counted twice each, and a trapezium that is not parallelogram is counted once each. Therefore, we need to subtract the number of parallelograms from the answer. A trapezium is a parallelogram if and only if the two diagonals’ midpoints coincide, so find the midpoint between each of \(\frac{N(N-1)}{2}\) possible pairs, and for each midpoint coordinates \(y\):
- subtract \(\frac{d_y(d_y-1)}{2}\) from the answer, if there are \(d_y\) pairs with midpoint \(y\).
Now every trapezium is counted exactly once, so this algorithm yields a correct answer.
Implementation
If you compute the slope as a floating-point value, precision errors may cause wrong coincidence verdict. Also, slopes like \(1/0\) and \(-1/0\) cause issues. Computing as rational numbers make it easy.
For more details, refer to the following sample code.
Sample code (C++)
#include <iostream> #include <cstdio> #include <vector> #include <array> #include <set> #include <map> using std::cin; using std::cout; using std::cerr; using std::endl; using std::pair; using std::make_pair; using std::vector; using std::min; using std::max; using std::array; using std::set; using std::map; #include <atcoder/all> using mint = atcoder::modint998244353; using atcoder::segtree; typedef long long int ll; ll n; vector<ll> x, y; ll mygcd (ll a, ll b) { if (b == 0) return a; return mygcd(b, a % b); } ll myabs (ll x) { return (x >= 0) ? x : (-x); } vector<pair<ll, ll> > slopes; vector<pair<ll, ll> > centers; ll countsamepair (const vector<pair<ll, ll> > &vec) { ll sum = 0; ll idx = 0; while (idx < vec.size()) { ll j = idx; while (j < vec.size() && vec[j] == vec[idx]) j++; ll len = j - idx; sum += len * (len-1) / 2; idx = j; } return sum; } void solve () { for (ll i = 0; i < n; i++) { for (ll j = i+1; j < n; j++) { // slope ll px = x[j] - x[i]; ll py = y[j] - y[i]; if (px == 0) { px = 0; py = 1; } else if (py == 0) { px = 1; py = 0; } else { if (px < 0) { px *= -1; py *= -1; } ll g = mygcd(myabs(px), myabs(py)); px /= g; py /= g; } slopes.push_back({px, py}); // center centers.push_back({x[i]+x[j], y[i]+y[j]}); } } ll ans = 0; sort(slopes.begin(), slopes.end()); ans += countsamepair(slopes); sort(centers.begin(), centers.end()); ans -= countsamepair(centers); cout << ans << "\n"; return; } int main (void) { std::ios_base::sync_with_stdio(false); cin.tie(nullptr); cin >> n; x.resize(n); y.resize(n); for (ll i = 0; i < n; i++) { cin >> x[i] >> y[i]; } solve(); return 0; }
posted:
last update: