题目连接:https://cn.vjudge.net/problem/CodeChef-ELHIDARR
题意:给你n个非递减的数,其中每个数都出现了k次,有一个特殊的数出现了至少一次,但小于k次,让你在60次的询问内找到这个特殊的数
由于只有一个特殊的数,先假设a[1]不是这个特殊的数,那么a[1]的重复次数就是k次 先二分找到k,
然后k+1这个位置的数和2*k+1这个位置的数相同那么就代表a[1]是这个特殊的数
为什么呢? 比如 11 222 333 444
找到了k=2 a[k+1] =2,a[2*k+1]=2 说明k不够大,所以第一个数就是结果
如果不相等的话,比如111 222 33 444
那么求出来的k就是真实的k
这个数列一共有4种数 分别是 1 2 3 4
然后再二分哪一种数 , l=1,r=n/k+1 m=代表二分到第m个数
然后k*m位的数与k*m+1位的数如果相等那么代表左边都是k的倍数,没有特殊的数,所以l=m+1;然后记录一下结果ans=l
如果不相等那么就是r=m-1;
注意
如果询问次数超过60,则wa
没有fflush(stdout)则超时
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 1e5+6;
bool vis[maxn];
int val[maxn];
int T,n;
int getval(int pos) {
int b;
if(pos > n || pos < 1) return -1;
if(vis[pos]) return val[pos];
vis[pos]=1;
printf("1 %d\n",pos);
fflush(stdout);
scanf("%d",&b);
val[pos]=b;
return b;
}
int main()
{
scanf("%d",&T);
while(T--) {
memset(vis,0,sizeof(vis));
scanf("%d",&n);
int a,b,k,ans;
a = getval(1);
int l=1,r=n;
while(l<=r) {
int m = l + r >>1;
b = getval(m);
if(b > a) r = m - 1;
else {
l = m + 1;
k = m;
}
}
if(getval(k + 1) == getval(2 * k +1 )) {
printf("2 %d\n",getval(1));
fflush(stdout);
}
else {
int l = 1, r = n / k + 1;
while(l <= r) {
int m = l + r >>1;
if(getval(m * k) == getval(m * k + 1)){
r = m - 1;
}else {
l = m + 1;
ans = l;
}
}
printf("2 %d\n",getval((ans-1) * k + 1));
fflush(stdout);
}
}
return 0;
}