『题解』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;
}
posted @ 2022-04-11 15:07  仙山有茗  阅读(29)  评论(0)    收藏  举报