All-Ukrainian School Olympiad in Informatics E: Points
問題概要
2次元平面上にN(<10^5)個の点が与えられる。各2点間の距離の2乗の総和を求める問題。
解法
まず、線形性からX成分とY成分は完全に分離して考えてよいことが分かる。
S:=Σ{x[i]^2}, K:=Σ{x[i]}とすると、各jに対して、Σ_i{(x[j]-x[i])^2}=Σ_i{x[j]^2 + x[i]^2 - 2*x[j]*x[i]} = Σ_i{x[i]^2} + N*x[j]^2 - 2*x[j]*Σ_i{x[i]} = S + N*x[j]^2 - 2*x[j]*Kなので、前処理でS,Kを計算しておけば定数時間でΣ_i{(x[j]-x[i])^2}を求められる。あとはこれを各jについて足し合わせて重複分2で割ればお終い。
感想
オーバーフローと、点が重なったときの処理を間違えてWA連発した。
#include <cstdio> #include <vector> #include <iostream> #include <set> using namespace std; typedef long long ulong; int N; inline long long sq(int x){ return (long long)x*x; } ulong solve(vector<int>& vs){ ulong ret = 0; ulong S = 0, K = 0; for(int i=0; i<N; i++){ S += sq(vs[0] - vs[i]); K += vs[0] - vs[i]; } for(int i=0; i<N; i++){ ret += S + (ulong)N*sq(vs[i] - vs[0]) + 2*(long long)(vs[i] - vs[0])*K; } return ret/2; } int main(){ vector<int> xs, ys; scanf("%d",&N); set<pair<int,int> > ss; for(int i=0; i<N; i++){ int x, y; scanf("%d%d",&x,&y); //if(ss.insert( make_pair(x,y)).second){ xs.push_back(x); ys.push_back(y); //} } N = xs.size(); ulong ans = solve(xs) + solve(ys); cout << ans << endl; return 0; }