mayoko’s diary

プロコンとかいろいろ。

Facebook Hacker Cup 2016 Qualification Round Boomerang Constellations

解法

点 A, B, C で AB = AC となるときの頂点 A について全探索します。
頂点 A からの他の頂点への距離を全部調べてソートすると, 例えば距離のリストとして 3, 3, 4, 4, 4 となったとすると, 距離 3 になって等しくなる頂点の組み合わせは 2C2 個あって, 距離 4 になって等しくなる頂点の組み合わせは 3C2 個あります。こんな感じで, 一般にある頂点から n 個距離が等しくなる頂点があったら, それらを使って nC2 通りのペアが作れます。

この解法は O(n^2 log n) でできるので, 時間内に答えを求められます。

ですが, すこし懸念なのは, AB = AC = BC となる点 A, B, C があった場合, 重複して 3 つの頂点の組を数えてしまう可能性があることです。ですが, このようなことは起こりえません。なぜなら, AB = AC = BC となるとき三角形 ABC は正三角形になり, AC ベクトルは AC ベクトルを 60 度回転したものになりますが, どちらも整数になるとすると sqrt(3) が有理数になるというよくあるアレが導かれて矛盾します。よって, AB = AC = BC となるような頂点の組は存在しません。

int X[2222], Y[2222];

ll square(ll x) {return x*x;}

void solve(int T) {
    int N;
    cin >> N;
    for (int i = 0; i < N; i++) {
        cin >> X[i] >> Y[i];
    }
    ll ans = 0;
    for (int i = 0; i < N; i++) {
        vector<ll> v(N);
        for (int j = 0; j < N; j++) {
            v[j] = (square(X[i]-X[j]) + square(Y[i]-Y[j]));
        }
        sort(v.begin(), v.end());
        int cur = 0;
        while (cur < N) {
            int i = cur;
            while (i < N && v[cur] == v[i]) i++;
            ll cnt = i-cur;
            ans += cnt*(cnt-1)/2;
            cur = i;
        }
    }
    cout << "Case #" << T << ": " << ans << endl;
}

int main() {
    cin.tie(0);
    ios::sync_with_stdio(false);
    int T;
    cin >> T;
    for (int t = 1; t <= T; t++) {
        solve(t);
    }
    return 0;
}