CF-1011D
常见交互题套路,有一个数字要猜,假设为 x x ;给计算机的数假设为 y y ,会得到以下三种回答:
但是,现在计算机坏了,对于某些询问会“说谎”;所谓“说谎”就是该回答 −1 − 1 的回答了 1 1 ;反之,该回答 1 1 的回答了 −1 − 1 。
抽象为 01 01 字符串, 0101 0101 表示第 1 1 、 3 3 次询问计算机会“说谎”;若询问的次数大于了 4 4 ,就会循环;即第 5 5 、 7 7 次会“说谎”。
现在,给这个 01 01 串的长度 n n ,以及 x x 的最大范围 m m (即 x≤m x ≤ m )。
还要求询问次数最多不超过 60 60 次。
1≤m≤1091≤n≤30 1 ≤ m ≤ 10 9 1 ≤ n ≤ 30
一开始完全没有思路,那个 01 01 串都没有给,猜上加猜?怎么猜?!
后来仔细一想,如果那个 01 01 串确定了,就是一个很简单的交互题了,直接二分就完了。
难点就在怎么确定那个 01 01 串?
其实,拿 1 1 去问个 n n 次就可以确定那个 01 01 串了;
如果回答为 0 0 ,那 x x 就是 1 1 ,这个就先不考虑了;
除此之外,对于每个询问,都应该满足 1<x 1 < x ,回答都应该是 1 1 ;如果不是,那这次就是在“说谎”;
这样恢复出那个 01 01 串后,这道题就解决了。
/**********************************************
*Author* :XzzF
*Created Time* : 2018/7/27 23:52:41
*Ended Time* : 2018/7/27 23:59:18
*********************************************/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
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;
}