1 条题解

  • 0
    @ 2026-8-20 15:01:29

    思路

    考虑一般的找最值方法是什么,这里以最大值为例。

    显然就是擂台法,即先钦定第一个值为最大值,然后依次向后比较,出现比它大的就替换,最终得到的值就是最值。

    假如有 NN 个数,那么需要比较 N1N-1 次,但是这题需要同时找出最小值和最大值,一般做法就是找两次,询问次数为 2N22N-2,不能通过,考虑优化。

    假如对于两个数 ai,aja_i,a_jai>aja_i>a_j,那么 aia_i 不可能为最小值,aja_j 不可能为最大值,证明显然。

    于是先对所有数两两询问,便可以将所有数分成两组,第一组中为不可能是最大值的数,第二组为不可能是最小值的数,于是最小值一定在第一组,最大值一定在第二组,再使用一般的找最值方法即可。询问次数为 32N\dfrac{3}{2} N,可以通过。

    代码 1

    注意 N=1N=1 时的特殊情况。

    #include <bits/stdc++.h>
    using namespace std;
    int Compare(int X,int Y);
    void Answer(int X,int Y);
    vector<int> b,s;
    void Ramen(int N){
    	if(N==1){
    		Answer(0,0);
    		return;
    	}
    	for(int x,i=0;i<N-1;i+=2){
    		x=Compare(i,i+1);
    		if(x==1) b.push_back(i),s.push_back(i+1);
    		else b.push_back(i+1),s.push_back(i);
    	}
    	if(N%2){
    		int x=Compare(N-2,N-1);
    		if(x==1) s.push_back(N-1);
    		else b.push_back(N-1);
    	}
    	int B=b[0],S=s[0];
    	for(int x,i=1;i<b.size();i++){
    		x=Compare(B,b[i]);
    		if(x==-1) B=b[i];
    	}
    	for(int x,i=1;i<s.size();i++){
    		x=Compare(S,s[i]);
    		if(x==1) S=s[i];
    	}
    	Answer(S,B);
    }
    

    如果你不想写这么多代码怎么办呢?有的兄弟,有的。在 c++ 中有一个函数 minmax_element,作用是在 32N\dfrac{3}{2}N 次比较内找出序列最小值与最大值,该函数实现方法跟以上思路完全一致,于是我们便只用三行写完了本题代码。

    代码 2

    #include <bits/stdc++.h>
    using namespace std;
    int Compare(int X,int Y);
    void Answer(int X,int Y);
    int a[405];
    void Ramen(int N){
    	for(int i=0;i<N;i++) a[i]=i;
    	auto [mn,mx]=minmax_element(a,a+N,[](int x,int y){return Compare(x,y)==-1;});
    	Answer(*mn,*mx);
    }
    
    • 1

    信息

    ID
    4675
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    3
    已通过
    2
    上传者