首页 >

最大 FST 距离

# 方法一:暴力解法,但超时
n = int(input())
num_list = list(map(int, input().split()))

max_FST = 0
for i in range(n):    # 任意两点循环计算,将最大值通过max()选出
    for j in range(n):
        max_FST = max(max_FST, abs((i+1)**2-(j+1)**2)+abs(num_list[i]**2-num_list[j]**2))

print(max_FST)

# 方法二:设i^2为Xi,设Ai^2为Yi,则原式可化为dist=|(Xi-Xj)|+|(Yi-Yj)|
# 若(Xi, Yi)是坐标点,则我们要求两点的横纵坐标之差的绝对值的和
# 将绝对值展开得到四个式子
# 1:(Xi±Yi)-(Xj±Yj)  
# 2:(-Xi±Yi)-(-Xj±Yj)    观察可知,第二组式子可由第一组式子的基础上添加负号得来
# 故选择第一组式子,1:(Xi+Yi)-(Xj+Yj)    2:(Xi-Yi)-(Xj-Yj)
# 而上述两个式子中只出现了两种元素:Xi+Yi和Xi-Yi
# 故只需求出两者各自的max和min,相减取最大值即可
n = int(input())
num_list = list(map(int, input().split()))

jia_list = []
jian_list = []
for i in range(n):    # 存入x+y和x-y的所有值
    x = (i + 1) ** 2
    y = num_list[i] ** 2
    jia_list.append(x + y)
    jian_list.append(x - y)

# 根据两个式子计算一个最大的
max_FST = max(max(jia_list) - min(jia_list), max(jian_list) - min(jian_list))
print(max_FST)
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
    long long n;cin>>n;
    vector<long long> x;
    vector<long long> y;
    for(long long i=1;i<=n;i++){
        long long a;cin>>a;
        x.push_back(i*i+a*a);
        y.push_back(a*a-i*i);   
    }
    sort(x.begin(),x.end());
    sort(y.begin(),y.end());
    long long n1=x[n-1]-x[0],n2=y[n-1]-y[0];
    cout<<max(n1,n2);
}

发表于 2026-03-04 17:56:33 回复(0)
import java.io.*;
import java.util.*;

public class Main {
    public static void main(String[] args) throws IOException {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        sc.nextLine();  // 消耗掉换行符
        String[] parts = sc.nextLine().split(" ");
        long[] A = new long[n];
        for (int i = 0; i < n; i++) {
            A[i] = Long.parseLong(parts[i]);
        }

        // 计算x = i² + A_i²的最大最小值
        long maxX = Long.MIN_VALUE;
        long minX = Long.MAX_VALUE;
        // 计算y = i² - A_i²的最大最小值
        long maxY = Long.MIN_VALUE;
        long minY = Long.MAX_VALUE;

        for (int i = 0; i < n; i++) {
            // 注意索引是从1开始的
            long index = i + 1;
            long indexSq = index * index;
            long aSq = A[i] * A[i];

            long x = indexSq + aSq;
            long y = indexSq - aSq;

            maxX = Math.max(maxX, x);
            minX = Math.min(minX, x);
            maxY = Math.max(maxY, y);
            minY = Math.min(minY, y);
        }

        // 最大距离是两个差值中的较大者
        long maxDist = Math.max(maxX - minX, maxY - minY);
        System.out.println(maxDist);
    }
}

发表于 2025-09-02 11:43:46 回复(0)
const rl = require("readline").createInterface({ input: process.stdin });
var iter = rl[Symbol.asyncIterator]();
const readline = async () => (await iter.next()).value;

void (async function () {
    // Write your code here
    await readline();
    while ((line = await readline())) {
        var arr = line.split(" ").map(Number);
        // 可以转化成
        // arr[i] * arr[i] + i * i => max - min
        // arr[i] * arr[i] - i * i => max - min
        if (arr.length < 2) return console.log(0);
        // 定义初始值
        let maxU = BigInt(arr[0]) * BigInt(arr[0]) + BigInt(1) * BigInt(1);
        let minU = maxU;
        let maxV = BigInt(arr[0]) * BigInt(arr[0]) - BigInt(1) * BigInt(1);
        let minV = maxV;
        // 从第二位开始获取maxU minU maxV minV
        for (let i = 1; i < arr.length; i++) {
            let tempU =
                BigInt(arr[i]) * BigInt(arr[i]) + BigInt(i + 1) * BigInt(i + 1);
            let tempV =
                BigInt(arr[i]) * BigInt(arr[i]) - BigInt(i + 1) * BigInt(i + 1);
            maxU = tempU > maxU ? tempU : maxU;
            minU = tempU < minU ? tempU : minU;
            maxV = tempV > maxV ? tempV : maxV;
            minV = tempV < minV ? tempV : minV;
        }
        // 获取maxU-minU 和maxV-minV中的大数
        console.log((maxU - minU > maxV - minV ? maxU - minU : maxV - minV).toString());
    }
})();

发表于 2026-05-27 10:25:54 回复(0)

这道题是一道非常经典的“数学公式变形(曼哈顿距离变种)”问题。对于刚学 C++ 的同学来说,很容易想到用两个for循环去两两配对算距离,但面对十万个数据,双重循环要算 100 亿次,程序绝对会运行超时 (TLE)。

能把 100 亿次的计算压缩到只需要一次循环,靠的是初中数学的“绝对值拆解”,以及 C++ 中极其重要的几个基础工具。

下面我将从核心解题思路关键 C++ 工具的用法,以及逐段代码详细拆解三个方面,为你把这道题揉碎了讲清楚。

一、 整体解题思路:神奇的“绝对值拆开”魔法

题目的距离公式是:

$$dist(i,j) = |i^2 - j^2| + |A_i^2 - A_j^2|$$

为了求最大值,我们可以默认靠后的元素减去靠前的元素,即设定 $i \ge j$。既然 $i \ge j$,那么 $i^2 - j^2$ 肯定是个大于等于 0 的数,所以第一层绝对值可以直接去掉

$$dist(i,j) = (i^2 - j^2) + |A_i^2 - A_j^2|$$

对于第二层绝对值 $|A_i^2 - A_j^2|$,它拆开后只有两种可能:

  1. 结果是正数(直接脱掉符号): $A_i^2 - A_j^2$

  2. 结果是负数(脱掉符号并翻转): $-A_i^2 + A_j^2$

我们把这两种可能分别代入公式,并合并同类项(把带 $i$ 的放一边,带 $j$ 的放一边):

情况 1: $(i^2 - j^2) + (A_i^2 - A_j^2) = (i^2 + A_i^2) - (j^2 + A_j^2)$

情况 2: $(i^2 - j^2) - (A_i^2 - A_j^2) = (i^2 - A_i^2) - (j^2 - A_j^2)$

极其重大的发现!

公式变成了两个特征值相减!我们只需要给每个数字计算两个“专属特征值”:

  • 特征值 $P$:$P_k = k^2 + A_k^2$

  • 特征值 $Q$:$Q_k = k^2 - A_k^2$

既然我们要在十万个数字里找最大的差值,我们根本不需要两两配对!就像找全班身高落差最大的两个人,你不需要把所有人两两拉出来比身高,你只需要找到“最高的人”和“最矮的人”减一下就行了。

所以,我们只需要找出:

  1. 所有 $P$ 里面的最大值减去最小值

  2. 所有 $Q$ 里面的最大值减去最小值

    比较这两个差值,谁更大,谁就是最终答案!

二、 核心 C++ 工具与语法详解(新手必看)

为什么代码里要用到下面这些东西?不用普通的写法可以吗?

1.long long(超长整型变量)

  • 为什么要用它?

    题目明确说,特征值 $A_i$ 最大可以达到 $10^9$。公式里我们要计算 $A_i^2$,也就是 $10^9 \times 10^9 = 10^{18}$。

    在 C++ 中,普通的int变量就像一个小盒子,最多只能装下约 21 亿。如果把 $10^{18}$ 塞进int里,盒子就会被“撑爆”(专业名词叫溢出),变成毫无意义的乱码负数。long long就像一个集装箱,容量高达 $9 \times 10^{18}$,完全能装下这里的平方运算。

2.max()和min()函数

  • 为什么要用它?

    在循环里,我们需要不断比较“当前算出的数字”和“历史最大值”,谁大就保留谁。初学者往往会写:

    C++
    if (P > max_P) {
        max_P = P;
    }

    用max()函数可以把上面的代码缩短成极其优雅的一行:max_P = max(max_P, P);。这不仅让代码变短,而且逻辑更清晰。

  • 用法是怎么样的?

    必须在代码最开头加上#include <algorithm>(算法工具箱)。

    调用max(A, B)时,计算机会自动比较 A 和 B,并把更大的那个数当作结果返回出来;min函数同理,返回较小的数。

3. 初始化技巧if (i == 1)

  • 为什么要用它?

    在寻找最大值时,很多新手喜欢把max_P初始设为 0。但万一算出来的 $P$ 全是负数(比如 -5, -10),那最大值就会被错误地卡在 0 上!

    最安全、最万能的套路是:拿第一个读进来的数据,当做最初的最大值和最小值。因为在只看了一个人的时候,他既是全班最高,也是全班最矮。后面的数据再去跟它比。

三、 逐段代码详细解析

下面我们把代码切开,一行行看看它是如何运转的。

C++
#include <iostream> #include <algorithm> // 包含 max() 和 min() 函数 using namespace std;

解释:

准备工具箱。<iostream>负责输入输出;<algorithm>算法库负责召唤我们的max和min函数。using namespace std;让我们省去std::cin的繁琐前缀。

C++
int main() { // 魔法加速咒语:提升读取速度,防止超时 ios_base::sync_with_stdio(false); cin.tie(NULL);

解释:

由于题目的输入量达到了 10 万级别,原生的cin读取速度比较慢。加上这两句“魔法加速咒语”,可以解除 C++ 输入输出的安全限速,防止读数据太慢而超时。

C++
long long n; cin >> n;

解释:

定义元素个数n并读入。

C++
// 记录 P 和 Q 的最大值和最小值 long long max_P, min_P, max_Q, min_Q;

解释:

准备 4 个超级账本变量。它们将分别用来随时记录特征值 $P$ 的最大值、最小值,以及特征值 $Q$ 的最大值、最小值。

C++
for (long long i = 1; i <= n; ++i) { long long a; cin >> a;

解释:

开一个循环,从下标 $i = 1$ 跑到 $i = n$(注意这里的 $i$ 也必须是long long,因为后面要算 $i \times i$)。每次循环,造一个临时变量a来接住当前输入的特征值。

C++
// 计算当前数字的两个特征值 P 和 Q long long P = i * i + a * a; long long Q = i * i - a * a;

解释:

整道题的灵魂所在!直接套用我们前面推导的合并公式,算出当前这个位置专属的特征值 $P$ 和 $Q$。

C++
// 如果是读取的第一个数字,直接把它作为初始的最大最小值 if (i == 1) {
            max_P = min_P = P;
            max_Q = min_Q = Q;
        }

解释:

记账的初始化阶段。如果是读进来的第一个数字($i == 1$),它没有任何人可以比较,所以它既是当前的最大值,也是当前的最小值。直接把它的 $P$ 和 $Q$ 填入 4 个账本中。

C++
else { // 否则,不断挑战并更新最大最小值 max_P = max(max_P, P);
            min_P = min(min_P, P);
            max_Q = max(max_Q, Q);
            min_Q = min(min_Q, Q);
        }
    }

解释:

如果这不是第一个数字,那就拿着刚算出来的 $P$ 去挑战旧的最高分max_P。

max(max_P, P)会选出旧纪录和新成绩里更大的那一个,然后再通过等号=重新存入max_P里。这就像是打擂台,谁强谁就留在王座上。最小值min也是同样的道理。

C++
// 最终答案就是 P 的最大差值 和 Q 的最大差值 中更大的那一个 long long ans = max(max_P - min_P, max_Q - min_Q); cout << ans << "\n"; return 0;
}

解释:

当十万个数字全部循环完后,擂台也打完了。

我们算出 $P$ 的极端落差:max_P - min_P。

算出 $Q$ 的极端落差:max_Q - min_Q。

这两者之中更大的那一个,就是我们在 100 亿种两两配对的可能性中,所能找到的最大 FST 距离!再次调用max函数选出最终赢家存入ans。

用cout输出答案,加上\n换行,程序圆满结束。


发表于 2026-05-20 17:28:44 回复(0)
n=int(input())
a=list(map(int,input().split()))
b1=sorted([(i+1)**2+a[i]**2 for i in range(len(a))])
b2=sorted([(i+1)**2-a[i]**2 for i in range(len(a))])
c1=b1[-1]-b1[0]
c2=b2[-1]-b2[0]
print(c1) if c1>c2 else print(c2)
发表于 2026-04-16 22:06:49 回复(0)
题目还有儿化音呢
发表于 2026-04-06 16:29:00 回复(0)
#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
using namespace std;

bool compare(pair<long long, long long> p1, pair<long long, long long> p2) {
    return p1.first > p2.first;
}

int main() {
    long long n; cin >> n;
    vector<pair<long long, long long>> v1, v2;
    for (long long i=1; i<=n; i++) {
        long long num; cin >> num;
        v1.push_back({i*i + num*num, i});
        v2.push_back({i*i - num*num, i});
    }
    sort(v1.begin(), v1.end(), compare);
    sort(v2.begin(), v2.end(), compare);
    long long FST = 0;
    FST = max(v2[0].first - v2[n-1].first, v1[0].first - v1[n-1].first);
    cout << FST << endl;
}
// 64 位输出请用 printf("%lld")

发表于 2026-02-24 21:54:36 回复(0)
# 方法一:暴力解法,但超时
n = int(input())
num_list = list(map(int, input().split()))

max_FST = 0
for i in range(n):    # 任意两点循环计算,将最大值通过max()选出
    for j in range(n):
        max_FST = max(max_FST, abs((i+1)**2-(j+1)**2)+abs(num_list[i]**2-num_list[j]**2))

print(max_FST)

# 方法二:设i^2为Xi,设Ai^2为Yi,则原式可化为dist=|(Xi-Xj)|+|(Yi-Yj)|
# 若(Xi, Yi)是坐标点,则我们要求两点的横纵坐标之差的绝对值的和
# 将绝对值展开得到四个式子
# 1:(Xi±Yi)-(Xj±Yj)  
# 2:(-Xi±Yi)-(-Xj±Yj)    观察可知,第二组式子可由第一组式子的基础上添加负号得来
# 故选择第一组式子,1:(Xi+Yi)-(Xj+Yj)    2:(Xi-Yi)-(Xj-Yj)
# 而上述两个式子中只出现了两种元素:Xi+Yi和Xi-Yi
# 故只需求出两者各自的max和min,相减取最大值即可
n = int(input())
num_list = list(map(int, input().split()))

jia_list = []
jian_list = []
for i in range(n):    # 存入x+y和x-y的所有值
    x = (i + 1) ** 2
    y = num_list[i] ** 2
    jia_list.append(x + y)
    jian_list.append(x - y)

# 根据两个式子计算一个最大的
max_FST = max(max(jia_list) - min(jia_list), max(jian_list) - min(jian_list))
print(max_FST)
发表于 2026-02-15 18:21:08 回复(0)
#include <iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<cmath>
#define ll long long
//      |i^2-j^2|+|Ai^2-Aj^2|  进行去绝对值 并将i,j移到一边 得到4种情况:
//      (i^2+Ai^2)-(j^2+Aj^2)    1
//       -(i^2+Ai^2)+(j^2+Aj^2)    2
//      (i^2-Ai^2)-(j^2-Aj^2)    3             
//      -(i^2-Ai^2)+(j^2-Aj^2)    4
//      
//       令:K1=n^2+An^2;   上面1-2式子得到最大值都是:最大K1减最小K1
//       令:K2=n^2-An^2;   上面3-4式子得到最大值都是:最大K2减最小K2    
int main() {
   vector<ll>v;
   vector<ll>v_k1;
   vector<ll>v_k2;
   ll n;
   cin>>n;
   for(ll i=0;i<n;i++){
      ll a;
      cin>>a;
      v.push_back(a);
   }
   for(ll i=0;i<n;i++){
      ll k1,k2;
      k1=(i+1)*(i+1)+v[i]*v[i];
      v_k1.push_back(k1);
      k2=(i+1)*(i+1)-v[i]*v[i];
      v_k2.push_back(k2);
   }
   sort(v_k1.begin(),v_k1.end());
   sort(v_k2.begin(),v_k2.end());
   ll FSTmax=0;
   FSTmax=max(v_k1[n-1]-v_k1[0],v_k2[n-1]-v_k2[0]);
   cout<<FSTmax;
  
   
}

发表于 2026-01-21 16:24:54 回复(0)
写Javascript的小伙伴记得开BigInt
发表于 2025-11-08 23:03:34 回复(0)
n = int(input())
A = list(map(int,input().split()))

dic_plus = {}
dic_minus = {}
for i in range(n):
    dic_plus[i+1] = A[i]**2+(i+1)**2
    dic_minus[i+1] = A[i]**2-(i+1)**2
sorted_dic_plus_keys = sorted(dic_plus.keys(),key=lambda x:dic_plus[x])
sorted_dic_minus_keys = sorted(dic_minus.keys(),key=lambda x:dic_minus[x])
answer = max(abs(sorted_dic_plus_keys[-1]**2-sorted_dic_plus_keys[0]**2)+abs(A[sorted_dic_plus_keys[-1]-1]**2-A[sorted_dic_plus_keys[0]-1]**2),abs(sorted_dic_minus_keys[-1]**2-sorted_dic_minus_keys[0]**2)+abs(A[sorted_dic_minus_keys[-1]-1]**2-A[sorted_dic_minus_keys[0]-1]**2))

print(answer)
发表于 2025-08-27 00:05:28 回复(0)
//本题做法:|i^2-j^2|+|ai^2-aj^2|存在2个变量(因为ai,aj可以用下标i,j表示出来)
//但是ij之间没有必然联系,我们要试着化简把i,ai放在一起j,aj一起
//|i^2-j^2|+|ai^2-aj^2|,分类讨论可以得到4种情况
//1:|i^2-j^2|>=0且|ai^2-aj^2|>=0 =>(i^2-j^2)+(ai^2-aj^2)=>(i^2+ai^2)-(j^2+aj^2)
//2: |i^2-j^2|>=0且|ai^2-aj^2|<0  =>(i^2-j^2)-(ai^2-aj^2)=>(i^2-ai^2)-(j^2-aj^2)
//3:   <0且>=0  =>-(i^2-j^2)+(ai^2-aj^2)=>-(i^2-ai^2)+(j^2-aj^2)
//4:   <0且<0   =>-(i^2-j^2)-(ai^2-aj^2)=>-(i^2+ai^2)+(j^2+aj^2)
//相似的放在一起直观的比较一下
//(i^2+ai^2)-(j^2+aj^2)     i>=j且ai>=aj的情况
//-(i^2+ai^2)+(j^2+aj^2)    i<j且ai<aj的情况
//观察可以知道都是()大的-()小的,我们排序后取用最大值-最小值就可以

//(i^2-ai^2)-(j^2-aj^2)     i>=j且ai<aj的情况
//-(i^2-ai^2)+(j^2-aj^2)    i<j且ai>=aj的情况
//这个也是同理,()大-()小
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
#define N 100005
//本题做法:|i^2-j^2|+|ai^2-aj^2|存在2个变量(因为ai,aj可以用下标i,j表示出来)
//但是ij之间没有必然联系,我们要试着化简把i,ai放在一起j,aj一起
//|i^2-j^2|+|ai^2-aj^2|,分类讨论可以得到4种情况
//1:|i^2-j^2|>=0且|ai^2-aj^2|>=0 =>(i^2-j^2)+(ai^2-aj^2)=>(i^2+ai^2)-(j^2+aj^2)
//2: |i^2-j^2|>=0且|ai^2-aj^2|<0  =>(i^2-j^2)-(ai^2-aj^2)=>(i^2-ai^2)-(j^2-aj^2)
//3:   <0且>=0  =>-(i^2-j^2)+(ai^2-aj^2)=>-(i^2-ai^2)+(j^2-aj^2)
//4:   <0且<0   =>-(i^2-j^2)-(ai^2-aj^2)=>-(i^2+ai^2)+(j^2+aj^2)
//相似的放在一起直观的比较一下
//(i^2+ai^2)-(j^2+aj^2)     i>=j且ai>=aj的情况
//-(i^2+ai^2)+(j^2+aj^2)    i<j且ai<aj的情况
//观察可以知道都是()大的-()小的,我们排序后取用最大值-最小值就可以

//(i^2-ai^2)-(j^2-aj^2)     i>=j且ai<aj的情况
//-(i^2-ai^2)+(j^2-aj^2)    i<j且ai>=aj的情况
//这个也是同理,()大-()小
int n;
int a[N];
int b[N],c[N];

signed main() {
    cin>>n;
    for(int i=1;i<=n;i++)cin>>a[i];
    for(int i=1;i<=n;i++){
        b[i]=i*i+a[i]*a[i];
        c[i]=i*i-a[i]*a[i];
    }
    sort(b+1,b+1+n);
    sort(c+1,c+1+n);
    int ans=0;
    ans=max(b[n]-b[1],c[n]-c[1]);
    cout<<ans<<endl;
    return 0;
}

发表于 2025-08-24 10:09:56 回复(0)