E题:Jump Distance Sum
标签:思维
题意:在坐标平面上,有
N
N
N个点
P
1
,
P
2
,
…
,
P
N
P_1,P_2,…,P_N
P1,P2,…,PN,其中点
P
i
P_i
Pi的坐标为
(
X
i
,
Y
i
)
(X_i,Y_i)
(Xi,Yi)。
两点
A
A
A与
B
B
B之间的距离
d
i
s
t
(
A
,
B
)
dist(A,B)
dist(A,B)定义如下:
一只兔子最初位于点
A
A
A。位置为
(
x
,
y
)
(x,y)
(x,y)的兔子可以跳跃到
(
x
+
1
,
y
+
1
)
、
(
x
+
1
,
y
−
1
)
、
(
x
−
1
,
y
+
1
)
(x+1,y+1) 、 (x+1,y−1) 、 (x−1,y+1)
(x+1,y+1)、(x+1,y−1)、(x−1,y+1)或
(
x
−
1
,
y
−
1
)
(x−1,y−1)
(x−1,y−1) 。
d
i
s
t
(
A
,
B
)
dist(A,B)
dist(A,B)被定义为从
A
A
A点到
B
B
B点所需的最少跳跃次数。
如果经过任意次数的跳跃都无法从点
A
A
A到达点
B
B
B,则设为
d
i
s
t
(
A
,
B
)
=
0
dist(A,B)=0
dist(A,B)=0。
计算总和
∑
i
=
1
N
−
1
∑
j
=
i
+
1
N
dist
(
P
i
,
P
j
)
\displaystyle\sum_{i=1}^{N-1}\displaystyle\sum_{j=i+1}^N \text{dist}(P_i,P_j)
i=1∑N−1j=i+1∑Ndist(Pi,Pj)
题解:兔子的移动是对角移动,不太方便进行操作。我们可以把坐标轴旋转
45
%
45\%
45%,并缩放
2
\sqrt2
2倍。那么
(
x
,
y
)
(x,y)
(x,y)点移动到
(
x
+
y
,
x
−
y
)
(x+y,x-y)
(x+y,x−y)。比如
(
2
,
2
)
(2,2)
(2,2)变成
(
2
2
,
0
)
(2\sqrt2,0)
(22,0),放大
2
\sqrt2
2倍,为
(
4
,
0
)
(4,0)
(4,0)。
原来位置为
(
x
,
y
)
(x,y)
(x,y)的兔子可以跳跃到
(
x
+
1
,
y
+
1
)
、
(
x
+
1
,
y
−
1
)
、
(
x
−
1
,
y
+
1
)
(x+1,y+1) 、 (x+1,y−1) 、 (x−1,y+1)
(x+1,y+1)、(x+1,y−1)、(x−1,y+1)或
(
x
−
1
,
y
−
1
)
(x−1,y−1)
(x−1,y−1) 。
我们转换后兔子可以从
(
x
+
y
,
x
−
y
)
(x+y,x-y)
(x+y,x−y)跳跃到
(
x
+
y
+
2
,
x
−
y
)
、
(
x
+
y
,
x
−
y
+
2
)
、
(
x
+
y
,
x
−
y
−
2
)
(x+y+2,x−y)、 (x+y,x−y+2) 、 (x+y,x−y−2)
(x+y+2,x−y)、(x+y,x−y+2)、(x+y,x−y−2)和
(
x
+
y
−
2
,
x
−
y
)
(x+y−2,x−y)
(x+y−2,x−y)
转换成更通用的式子:兔子可以从
(
x
,
y
)
(x,y)
(x,y)跳跃到
(
x
+
2
,
y
)
、
(
x
,
y
+
2
)
、
(
x
,
y
−
2
)
(x+2,y)、 (x,y+2) 、 (x,y−2)
(x+2,y)、(x,y+2)、(x,y−2)和
(
x
−
2
,
y
)
(x−2,y)
(x−2,y)
那么我们观察到每次跳跃的距离都是偶数,也就是说如果
A
=
(
x
1
,
y
1
)
,
B
=
(
x
2
,
y
2
)
A=(x_1,y_1),B=(x_2,y_2)
A=(x1,y1),B=(x2,y2),
∣
x
1
−
x
2
∣
|x_1-x_2|
∣x1−x2∣不能被
2
2
2整除,或者
∣
y
1
−
y
2
∣
|y_1-y_2|
∣y1−y2∣不能被
2
2
2整除,那么兔子就无法从
A
A
A到达
B
B
B。
对于能到达的情况跳跃的最少次数显然等于
1
2
(
∣
x
1
−
x
2
∣
+
∣
y
1
−
y
2
∣
)
\frac{1}{2}(\lvert x_1-x_2\rvert+\lvert y_1-y_2\rvert)
21(∣x1−x2∣+∣y1−y2∣)。
也就是说对于能够相互到达的两个点
A
A
A和
B
B
B,他们的转化后的
x
x
x坐标的奇偶性和
y
y
y坐标的奇偶性必须相同。
我们可以统计一下对应转化后的
x
x
x奇/偶,
y
y
y奇/偶的情况。然后去求一下对应情况下的跳跃次数。
这边举个例子:假设
x
x
x奇,
y
y
y奇的情况,得到的
x
x
x的序列为
1
3
8
13
1\ \ \ 3\ \ \ 8\ \ \ 13
1 3 8 13
第二个 3 到 1 的距离为 1 段 2 的距离。
第三个 8 到前面两个点的距离为 2 段 8 的距离减去前缀前两个距离之和,即
2
∗
8
−
(
1
+
3
)
2*8-(1+3)
2∗8−(1+3)
第四个 13 到前面两个点的距离为 3 段 13 的距离减去前缀 3 个距离之和,即
3
∗
13
−
(
1
+
3
+
8
)
3*13-(1+3+8)
3∗13−(1+3+8)
注意题目中,转化后是
2
2
2的距离跳的,所以跳跃的次数最后要除以
2
2
2。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n, X, Y, ans = 0;
vector<ll> x[2][2], y[2][2];
int main() {
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> X >> Y;
x[(X+Y)%2][abs(X-Y)%2].push_back(X+Y);
y[(X+Y)%2][abs(X-Y)%2].push_back(X-Y);
}
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
int nx = x[i][j].size();
int ny = y[i][j].size();
if (nx == 0) continue;
sort(x[i][j].begin(), x[i][j].end());
sort(y[i][j].begin(), y[i][j].end());
ll prex = x[i][j][0], prey = y[i][j][0];;
for (int k = 1; k < nx; k++) {
ans += k * x[i][j][k] - prex;
prex += x[i][j][k];
}
for (int k = 1; k < ny; k++) {
ans += k * y[i][j][k] - prey;
prey += y[i][j][k];
}
}
}
cout << ans / 2;
return 0;
}