Points

Points

Created by LXC on Wed Jun 14 13:11:47 2023

https://codeforces.com/problemset/problem/76/E

ranting: 1700

tag: implementation, math

problem

给出二维平面上的n个整数坐标点。

求所有两个坐标的直线距离的平方之和。

1n105

solution

暴力做法是枚举任意两个点求其距离的平方,然后累加到答案中。O(n2)时间复杂度会超时。

现在考虑优化到O(n2).

对于两个点(x1,y1)(x2,y2)的距离的平方计算公式为(x2x1)2+(y2y1)2,也就是说我们可以分别计算x和y的贡献。

举个例子来说,如果给出的坐标为(x1,y1),(x2,y2),(x3,y3)

答案应当是(x2x1)2+(y2y1)2+(x3x1)2+(y3y1)2+(x3x2)2+(y3y2)2

可以拆分为(x2x1)2+(x3x1)2+(x3x2)2(y2y1)2+(y3y1)2+(y3y2)2

可以给x以及y坐标排序再寻找相邻前缀是否存在子问题的关系。

设给出的n个坐标的x值排序后为x1,x2,,xn;设给出的n个坐标的y值排序后为y1,y2,,yn

定义状态Rix1,x2,,xi+1中任意两个点之间的距离平方和。

为方便计算RiRi1的递推关系,设dx是排序后相邻两个坐标的距离,dxi=xi+1xi

我们观察一个例子dx1=a,dx2=b,dx3=c,dx4=d

R1=a2

R2=R1+(a+b)2+b2=R1+2b2+2ab+a2

R3=R2+(a+b+c)2+(b+c)2+c2=R2+3c2+2(a+2b)c+R2R1

R4=R3+(a+b+c+d)2+(b+c+d)2+(c+d)2+d2=R3+4d2+2(a+2b+3c)d+R3R2

通过观察得到递推式Ri=2Ri1Ri2+idxi2+2ridxi,其中R0=0,R1=dx12ri=j=1ijdxj

对于n个点的y值同理可以定义状态Ciy1,y2,,yi+1中任意两个点之间的距离平方和。dyi=yi+1yi,ci=j=1ijdyj。得到递推式Ci=2Ci1Ci2+idyi2+2cidyi,其中C0=0,C1=dy12

至此Rn1+Cn1为所求。

code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61

#include <bits/stdc++.h>
#define SINGLE_INPUT
#define ll long long
#define ull unsigned long long
#define N 100005
#define MOD 998244353
using namespace std;

ll x[N], y[N];
ll dx[N], dy[N];
ll r[N], c[N];
ll R[N], C[N];

void sol() {
int n;
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> x[i] >> y[i];
}
sort(x + 1, x + n + 1);
sort(y + 1, y + n + 1);
for (int i = 1; i < n; i++) {
dx[i] = x[i + 1] - x[i];
dy[i] = y[i + 1] - y[i];
// cout << i << " " << dx[i] << " " << dy[i] << "\n";
}

for (int i = 1; i < n; i++) {
r[i] += r[i - 1] + i * dx[i];
c[i] += c[i - 1] + i * dy[i];
// cout << i << " " << r[i] << " " << c[i] << "\n";
}
R[1] = dx[1] * dx[1];
C[1] = dy[1] * dy[1];
for (int i = 2; i < n; i++) {
R[i] =
2 * R[i - 1] - R[i - 2] + i * dx[i] * dx[i] + 2 * r[i - 1] * dx[i];
C[i] =
2 * C[i - 1] - C[i - 2] + i * dy[i] * dy[i] + 2 * c[i - 1] * dy[i];
}
cout << R[n - 1] + C[n - 1] << "\n";
}

int main() {
cout << setprecision(15) << fixed;
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
#ifndef SINGLE_INPUT
int t;
cin >> t;
while (t--) {
sol();
}
#else
sol();
#endif
return 0;
}