[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;
}

浙公网安备 33010602011771号