1 条题解
-
0
题解:棋盘王棋距离和的高效计算
问题分析
本题要求计算两个玩家的所有王棋之间的两两距离之和,其中距离定义为切比雪夫距离(Chebyshev距离):
$$d((x_1,y_1),(x_2,y_2)) = \max(|x_1-x_2|, |y_1-y_2|) $$朴素计算需要 时间( 为棋子数),不可行。需要优化到 。
核心观察与坐标变换
1. 坐标变换
关键技巧:引入变换坐标:
在变换后,切比雪夫距离转化为曼哈顿距离的一半:
2. 距离和分解
对于棋子集合,总距离和:
$$\sum_{i<j} \max(|dx|,|dy|) = \frac{1}{2} \left( \sum_{i<j} |u_i-u_j| + \sum_{i<j} |v_i-v_j| \right) $$问题分解为两个一维绝对差和问题。
3. 一维绝对差和计算
对于一维点集 (已排序):
$$\sum_{i<j} |p_i-p_j| = \sum_{i=1}^k p_i \cdot (2i - k - 1) $$推导:排序后 , 对于 ,有 个点比它小, 个点比它大,所以贡献为 。
算法框架
第一步:收集坐标并变换
代码中的巧妙处理:
-
第一次扫描:按对角线 收集点,计算 坐标的贡献
- 对于满足 的点, 为常数
- 实际上这里计算的是 坐标的绝对差和
- 但代码通过特殊方式避免了显式存储所有点
-
第二次扫描:按对角线 收集点,计算 坐标的贡献
第二步:一维距离和计算
函数
get(point *poi, int n, bool calx):- 如果
calx = true:按 坐标排序并计算 - 如果
calx = false:按 坐标排序并计算
实现方式:
ll get(point *poi, int n, bool calx) { ll ret = 0, got = 0; if (calx) for (int i = 1; i <= n; i++) ret += 1ll * (i - 1) * poi[i].x - got, got += poi[i].x; else for (int i = 1; i <= n; i++) ret += 1ll * (i - 1) * poi[i].y - got, got += poi[i].y; return ret; }这里利用了公式 $\sum_{i<j} |p_i-p_j| = \sum_{i=1}^k p_i \cdot (2i-k-1)$,但实现更简洁:
$$ret = \sum_{i=1}^k [(i-1) \cdot p_i - (p_1 + \dots + p_{i-1})] $$等价于 $\sum_{i=1}^k p_i \cdot (i-1) - \sum_{j=1}^{i-1} p_j$。
第三步:合并结果
总距离和 =
代码细节解析
第一次扫描
for (int x = 2; x <= n + m; x++) // x = x+y 的和 for (int i = 1; i <= n; i++) { if (x - i >= 1 && x - i <= m) { // 计算 y = x-i if (mp[i][x - i] == 'M') mir[++mcnt] = (point){x, x - 2*i}; // 存储 (u, v) } }这里:
x是 的值x - 2*i = (x+y) - 2x = y - x = -v,但符号不影响绝对差
实际上存储的是变换后的坐标,但为了计算 坐标差,只用了第一个分量。
第二次扫描
for (int y = 1 - m; y <= n - 1; y++) // y = x-y 的差 for (int j = 1; j <= m; j++) { if (y + j >= 1 && y + j <= n) { // 计算 x = y+j if (mp[y + j][j] == 'M') mir[++mcnt] = (point){y + 2*j, y}; // 存储 (u, v) } }排序隐含
注意:
get函数假设输入数组已按相应坐标排序。由于扫描时是按特定顺序(对角线顺序),得到的数组可能已经有序,或需要显式排序(代码中未显示排序,可能依赖输入特性)。
复杂度分析
- 时间复杂度:
- 两次扫描棋盘:
get函数:, 为棋子数
- 空间复杂度: 存储所有棋子
对于 ,,完全可行。
正确性证明
1. 坐标变换的正确性
切比雪夫距离与曼哈顿距离关系:
$$\max(|dx|,|dy|) = \frac{|dx+dy| + |dx-dy|}{2} = \frac{|du|+|dv|}{2} $$2. 距离和分解
由于绝对值函数的线性可加性:
$$\sum_{i<j} \frac{|du|+|dv|}{2} = \frac{1}{2}\left(\sum_{i<j}|du| + \sum_{i<j}|dv|\right) $$3. 一维公式的正确性
对于排序后的 :
$$\sum_{i<j} (p_j - p_i) = \sum_{i=1}^k p_i \cdot [(k-i) - (i-1)] = \sum_{i=1}^k p_i \cdot (k-2i+1) $$代码中的公式是等价变形。
算法优势
- 避免显式两两计算:将 降为
- 分离坐标维度:二维问题分解为两个一维问题
- 利用扫描顺序:可能避免显式排序
- 内存高效:只需要存储棋子坐标,无需邻接矩阵
总结
本题是一道距离计算优化的经典问题,主要考察:
- 坐标变换技巧:Chebyshev距离到曼哈顿距离的转化
- 一维距离和公式:排序后线性计算绝对差和
- 扫描线思想:按对角线收集点,可能自然有序
- 问题分解能力:将复杂二维问题分解为简单一维问题
算法的核心在于通过巧妙的坐标变换,将难以直接计算的二维距离和转化为两个一维绝对差和,从而大幅降低时间复杂度。
这种"坐标变换+一维公式"的方法是计算几何和组合优化中的常用技巧,适用于各种距离度量下的聚合计算。
- 1
信息
- ID
- 5839
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者