题目链接
题目描述
给定 个元素,第
个元素具有特征值
。定义两个元素
和
之间的 FST 距离为:
请计算所有元素对中的最大 FST 距离。
解题思路
这是一个求解最大距离的问题。如果采用暴力法,遍历所有可能的元素对 来计算距离,时间复杂度将是
,对于
较大的情况会超时。因此,我们需要对公式进行分析和优化。
1. 公式分析与几何解释
FST 距离的公式 实际上是二维平面上两点之间的曼哈顿距离。
我们可以将每个元素
看作是平面上的一个点
,其坐标为
。这样,FST 距离
就是点
和
之间的曼哈顿距离。问题就转化为了:在由
个点组成的点集中,找出曼哈顿距离最远的一对点。
2. 曼哈顿距离与切比雪夫距离的转换 直接在点集中寻找最远曼哈顿距离仍然不容易。这里有一个重要的几何变换技巧:将坐标系旋转45度,可以实现曼哈顿距离和切比雪夫距离的相互转换。
对于任意两点 和
,它们的曼哈顿距离为
。
我们进行坐标变换,令
和
。那么在新坐标系中,点
变为
。
可以证明,原坐标系中的曼哈顿距离等于新坐标系中的切比雪夫距离,即:
3. 问题简化
现在,问题变成了在新坐标系中寻找最远的切比雪夫距离。一个点集中最远的切比雪夫距离为:
而
就是所有
值中的最大值与最小值的差,即
max(u) - min(u)
。同理,。
所以,最终的最大 FST 距离就是 max(max(u) - min(u), max(v) - min(v))
。
4. 算法步骤
- 根据原问题,我们定义的点的坐标是
。
- 进行坐标变换,计算每个元素
对应的新坐标分量
和
:
- 我们只需要遍历一次所有元素,在遍历过程中同时找出
的最大值、最小值和
的最大值、最小值。
- 计算出
max_u - min_u
和max_v - min_v
。 - 这两者中的较大值就是我们要求的最大 FST 距离。
这个算法只需要一次遍历,时间复杂度为 。由于
和
的值可能很大,需要使用长整型(
long long
)来存储。
代码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int n;
cin >> n;
long long max_u = -2e18, min_u = 2e18;
long long max_v = -2e18, min_v = 2e18;
for (long long i = 1; i <= n; ++i) {
long long a;
cin >> a;
long long u = i * i + a * a;
long long v = i * i - a * a;
max_u = max(max_u, u);
min_u = min(min_u, u);
max_v = max(max_v, v);
min_v = min(min_v, v);
}
cout << max(max_u - min_u, max_v - min_v) << endl;
return 0;
}
import java.util.Scanner;
import java.lang.Math;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
long[] a = new long[n];
for (int i = 0; i < n; i++) {
a[i] = sc.nextLong();
}
long maxU = Long.MIN_VALUE;
long minU = Long.MAX_VALUE;
long maxV = Long.MIN_VALUE;
long minV = Long.MAX_VALUE;
for (long i = 0; i < n; i++) {
long idx = i + 1;
long val = a[(int)i];
long u = idx * idx + val * val;
long v = idx * idx - val * val;
maxU = Math.max(maxU, u);
minU = Math.min(minU, u);
maxV = Math.max(maxV, v);
minV = Math.min(minV, v);
}
long dist = Math.max(maxU - minU, maxV - minV);
System.out.println(dist);
}
}
import sys
def solve():
n = int(sys.stdin.readline())
a = list(map(int, sys.stdin.readline().split()))
max_u = -float('inf')
min_u = float('inf')
max_v = -float('inf')
min_v = float('inf')
for i in range(n):
idx = i + 1
val = a[i]
u = idx*idx + val*val
v = idx*idx - val*val
max_u = max(max_u, u)
min_u = min(min_u, u)
max_v = max(max_v, v)
min_v = min(min_v, v)
result = max(max_u - min_u, max_v - min_v)
print(result)
solve()
算法及复杂度
- 算法:坐标变换 + 单次遍历
- 时间复杂度:我们只需要对输入数组进行一次遍历,以找到变换后坐标分量的最大值和最小值。因此,总时间复杂度为
。
- 空间复杂度:我们只需要常数个变量来存储最大值和最小值,因此空间复杂度为
(不考虑输入数组的存储)。