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;
}