『题解』CodeForces CF1656A Good Pairs
题目大意
给定一个长度为 \(n\) 的数列 \(a\),请找出任意一个数对 \((i,j)\),满足:
- \(1 \le i,j \le n\)。
- \(\forall 1 \le k \le n,|a_i-a_k| + |a_k-a_j| = |a_i-a_j|\)。
多组数据。
思路
先来尝试将两个数放在一个数轴上,那么 \(|a-b|\) 代表的就是 \(a\) 与 \(b\) 之间的距离。
那么 \(|a_i-a_k|,|a_k-a_j|,|a_i-a_j|\) 就分别表示 \(a_i\) 到 \(a_k\) 的距离,\(a_k\) 到 \(a_j\) 的距离和 \(a_i\) 到 \(a_j\) 的距离。
这样就能清楚地看到题目中第二个条件的含义:\(a_i\) 到 \(a_k\) 的距离加 \(a_k\) 到 \(a_j\) 的距离必须等于 \(a_i\) 到 \(a_j\) 的距离。
\(\forall\) 符号的意思是“任意的”,这里表示要求从 \(1\) 到 \(n\) 中任意选取一个 \(k\),都需要满足 \(|a_i-a_k| + |a_k-a_j| = |a_i-a_j|\)(可以无视这句话)。
\(a_i\) 到 \(a_k\) 的距离加 \(a_k\) 到 \(a_j\) 的距离必须等于 \(a_i\) 到 \(a_j\) 的距离。
很容易看出来 \(a_i \le a_k \le a_j\) 或者 \(a_j \le a_k \le a_i\),\(a_k\) 一定处于 \(a_i\) 和 \(a_j\) 中间。
这样就很好办了,取出最大最小值的下标作为数对 \((i,j)\),就可以满足所有情况了。
代码
#include <iostream>
using namespace std;
template<typename T=int>
inline T read(){
T X=0; bool flag=1; char ch=getchar();
while(ch<'0' || ch>'9'){if(ch=='-') flag=0; ch=getchar();}
while(ch>='0' && ch<='9') X=(X<<1)+(X<<3)+ch-'0',ch=getchar();
if(flag) return X;
return ~(X-1);
}
template<typename T=int>
inline void write(T X){
if(X<0) putchar('-'),X=~(X-1);
T s[20],top=0;
while(X) s[++top]=X%10,X/=10;
if(!top) s[++top]=0;
while(top) putchar(s[top--]+'0');
putchar(' ');
}
int t,n,x,minn,mini,maxn,maxi;
// minn 和 maxn 分别表示最小和最大值是多少
// mini 和 maxi 分别表示最小和最大值在数组中的下标
int main(){
t=read();
while(t--){
n=read();
minn=0x3f3f3f3f,maxn=-0x3f3f3f3f; // 初始化
for(int i=1; i<=n; i++){
x=read();
if(x<minn){ // 更新最小值
minn=x;
mini=i;
}
if(x>maxn){ // 更新最大值
maxn=x;
maxi=i;
}
}
write(mini),write(maxi);
puts("");
}
return 0;
}

浙公网安备 33010602011771号