Official

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: