[CF1698D]Fixed Point Guessing

做题时间:2022.6.29

\(【题目描述】\)

这是一道交互题。评测机生成一个长度为 \(N(3\leq N\leq 10^4,n 是奇数)\) 的序列 \(a=[1,2,...,n]\) ,并交换 \(\frac{n-1}{2}\) 组互不相同的位置上的数字,最后有且仅有一个数字的位置不变,给出操作完的序列。你可以向评测机询问区间 \([l,r]\) 中的数按升序排列后的结果,询问次数不超过 \(15\) 次,最后你要求出这个位置不变的数。

\(【输入格式】\)

第一行一个整数 \(t\) 表示数据组数
每组数据第一行一个整数 \(N\)
第二行 \(N\) 个整数表示序列 \(a\)

\(【考点】\)

二分

\(【做法】\)

可以发现询问次数很少,且 \(\log 1000\)\(15\) 很接近,可以考虑二分。

每次查找一个 \([l,mid]\) ,想要判断位置不变的数是否在其中分几种情况讨论,如果 \([l,mid]\) 中的其中 \(k\) 个数与 \([l,mid]\) 之外的数进行了交换那么 大小\([l,mid]\) 中的数的个数就减去了 \(k\) ,而 \([l,mid]\) 内的数两两交换则不变。可以理解为,操作完成后,若 \([l,mid]\) 中的数全部被交换过,那么 大小\([l,mid]\) 内的数要么被交换出去,要么成对留下。因此若 \([l,mid]\) 区间中大小在 \([l,mid]\) 中的数有奇数个,说明位置不变的数就在其中。

\(【代码】\)

#include<iostream>
#include<cstdio>
#include<iomanip>
using namespace std;
const int N=1e4+50;
int a[N],t,n;
void Query(int x,int y)
{
    int cnt=0;
    cout<<"? "<<x<<" "<<y<<endl;
    for(int i=1;i<=y-x+1;i++) cin>>a[i];
    fflush(stdout);
}
int main()
{
    cin>>t;
    while(t--){
        cin>>n;
        int l=1,r=n;
        while(l<r){
            int mid=(l+r)>>1;
            Query(l,mid);
            int cnt=0;
            for(int i=1;i<=mid-l+1;i++){
                if(a[i]>=l&a[i]<=mid) cnt++;
            }
            if(cnt%2==0) l=mid+1;
            else r=mid;
        }
        cout<<"! "<<l<<endl;
        fflush(stdout);
    }
    return 0;
}
posted @ 2022-07-08 08:32  lxzy  阅读(42)  评论(0)    收藏  举报