题目链接:
题目大意:
常见交互题套路,有一个数字要猜,假设为 xx ;给计算机的数假设为 yy,会得到以下三种回答:
- 若 x<yx<y,回答 −1−1;
- 若 x==yx==y,回答 00;
- 若 x>yx>y,回答 11;
但是,现在计算机坏了,对于某些询问会“说谎”;所谓“说谎”就是该回答 −1−1 的回答了 11 ;反之,该回答 11 的回答了 −1−1。
抽象为 0101 字符串,01010101 表示第 11 、33 次询问计算机会“说谎”;若询问的次数大于了 44,就会循环;即第 55、77 次会“说谎”。
现在,给这个 0101 串的长度 nn,以及 xx 的最大范围 mm(即 x≤mx≤m)。
还要求询问次数最多不超过 6060 次。
数据范围:
1≤m≤1091≤n≤301≤m≤1091≤n≤30
解题思路:
一开始完全没有思路,那个 0101 串都没有给,猜上加猜?怎么猜?!
后来仔细一想,如果那个 0101 串确定了,就是一个很简单的交互题了,直接二分就完了。
难点就在怎么确定那个 0101 串?
其实,拿 11 去问个 nn 次就可以确定那个 0101 串了;
如果回答为 00 ,那 xx 就是 11,这个就先不考虑了;
除此之外,对于每个询问,都应该满足 1<x1<x ,回答都应该是 11 ;如果不是,那这次就是在“说谎”;
这样恢复出那个 0101 串后,这道题就解决了。
AC代码:
/**********************************************
*Author* :XzzF
*Created Time* : 2018/7/27 23:52:41
*Ended Time* : 2018/7/27 23:59:18
*********************************************/
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <string>
#include <iostream>
#include <vector>
#include <queue>
#include <set>
#include <stack>
#include <map>
using namespace std;
typedef long long LL;
const int inf = 1 << 30;
const LL INF = 1LL << 60;
int n, m;
bool lie[50]; //lie[i]为true表示第i次会说谎
int Recover(int y) {
printf("%d\n", y);
fflush(stdout);
int num;
scanf("%d", &num);
if(num == 0 || num == -2) exit(0);
return num;
}
bool check(int y, int cnt) {
printf("%d\n", y);
fflush(stdout);
int num;
scanf("%d", &num);
if(num == 0 || num == -2) exit(0);
if(num == 1) { //y < expect
if(lie[cnt]) return true;
else return false;
}
else if(num == -1) { //y > expect
if(lie[cnt]) return false;
else return true;
}
}
int main()
{
scanf("%d %d", &m, &n);
memset(lie, false, sizeof(lie));
for(int i = 0; i < n; i++) {
int val = Recover(1);
if(val == -1) lie[i] = true;
}
int l = 1, r = m;
int cnt = 0;
while(l <= r) {
int mid = (l + r) >> 1;
if(check(mid, cnt % n)) r = mid - 1; //忘了mod,WA了几发
else l = mid + 1;
cnt++;
}
return 0;
}