#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);
} 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);
}
}
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());
}
})();
这道题是一道非常经典的“数学公式变形(曼哈顿距离变种)”问题。对于刚学 C++ 的同学来说,很容易想到用两个for循环去两两配对算距离,但面对十万个数据,双重循环要算 100 亿次,程序绝对会运行超时 (TLE)。
能把 100 亿次的计算压缩到只需要一次循环,靠的是初中数学的“绝对值拆解”,以及 C++ 中极其重要的几个基础工具。
下面我将从核心解题思路、关键 C++ 工具的用法,以及逐段代码详细拆解三个方面,为你把这道题揉碎了讲清楚。
题目的距离公式是:
为了求最大值,我们可以默认靠后的元素减去靠前的元素,即设定 $i \ge j$。既然 $i \ge j$,那么 $i^2 - j^2$ 肯定是个大于等于 0 的数,所以第一层绝对值可以直接去掉:
对于第二层绝对值 $|A_i^2 - A_j^2|$,它拆开后只有两种可能:
结果是正数(直接脱掉符号): $A_i^2 - A_j^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$
既然我们要在十万个数字里找最大的差值,我们根本不需要两两配对!就像找全班身高落差最大的两个人,你不需要把所有人两两拉出来比身高,你只需要找到“最高的人”和“最矮的人”减一下就行了。
所以,我们只需要找出:
所有 $P$ 里面的最大值减去最小值。
所有 $Q$ 里面的最大值减去最小值。
比较这两个差值,谁更大,谁就是最终答案!
为什么代码里要用到下面这些东西?不用普通的写法可以吗?
为什么要用它?
题目明确说,特征值 $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}$,完全能装下这里的平方运算。
为什么要用它?
在循环里,我们需要不断比较“当前算出的数字”和“历史最大值”,谁大就保留谁。初学者往往会写:
if (P > max_P) {
max_P = P;
} 用max()函数可以把上面的代码缩短成极其优雅的一行:max_P = max(max_P, P);。这不仅让代码变短,而且逻辑更清晰。
用法是怎么样的?
必须在代码最开头加上#include <algorithm>(算法工具箱)。
调用max(A, B)时,计算机会自动比较 A 和 B,并把更大的那个数当作结果返回出来;min函数同理,返回较小的数。
为什么要用它?
在寻找最大值时,很多新手喜欢把max_P初始设为 0。但万一算出来的 $P$ 全是负数(比如 -5, -10),那最大值就会被错误地卡在 0 上!
最安全、最万能的套路是:拿第一个读进来的数据,当做最初的最大值和最小值。因为在只看了一个人的时候,他既是全班最高,也是全班最矮。后面的数据再去跟它比。
下面我们把代码切开,一行行看看它是如何运转的。
#include <iostream> #include <algorithm> // 包含 max() 和 min() 函数 using namespace std;
解释:
准备工具箱。<iostream>负责输入输出;<algorithm>算法库负责召唤我们的max和min函数。using namespace std;让我们省去std::cin的繁琐前缀。
int main() { // 魔法加速咒语:提升读取速度,防止超时 ios_base::sync_with_stdio(false); cin.tie(NULL);
解释:
由于题目的输入量达到了 10 万级别,原生的cin读取速度比较慢。加上这两句“魔法加速咒语”,可以解除 C++ 输入输出的安全限速,防止读数据太慢而超时。
long long n; cin >> n;
解释:
定义元素个数n并读入。
// 记录 P 和 Q 的最大值和最小值 long long max_P, min_P, max_Q, min_Q;
解释:
准备 4 个超级账本变量。它们将分别用来随时记录特征值 $P$ 的最大值、最小值,以及特征值 $Q$ 的最大值、最小值。
for (long long i = 1; i <= n; ++i) { long long a; cin >> a;
解释:
开一个循环,从下标 $i = 1$ 跑到 $i = n$(注意这里的 $i$ 也必须是long long,因为后面要算 $i \times i$)。每次循环,造一个临时变量a来接住当前输入的特征值。
// 计算当前数字的两个特征值 P 和 Q long long P = i * i + a * a; long long Q = i * i - a * a;
解释:
整道题的灵魂所在!直接套用我们前面推导的合并公式,算出当前这个位置专属的特征值 $P$ 和 $Q$。
// 如果是读取的第一个数字,直接把它作为初始的最大最小值 if (i == 1) { max_P = min_P = P; max_Q = min_Q = Q; }
解释:
记账的初始化阶段。如果是读进来的第一个数字($i == 1$),它没有任何人可以比较,所以它既是当前的最大值,也是当前的最小值。直接把它的 $P$ 和 $Q$ 填入 4 个账本中。
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也是同样的道理。
// 最终答案就是 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换行,程序圆满结束。
#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") #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;
} #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;
}