CF1039B
题意
一个人初始在 \(p\) 点,你要通过不超过 \(4500\) 次询问问出这个人的位置。每次询问问这个人是否在 \([l,\ r]\) 范围内,每次询问后这个人会从 \(p\) 移动到 \([max(1,\ p\ -\ x),\ min(n,\ p\ +\ x)]\) 中的一个点,移动与询问无关。
\(1\ \leq\ n\ \leq\ 10^{18},\ 0\ \leq\ k\ \leq\ 10,\ 1\ \leq\ p\ \leq\ n\)
做法1
大范围二分,小范围随机。
随机函数:
\(rand()\) 效果很差,生成数据范围小,并且周期较短。\(rand()\) 和取模一起用的时候概率也会不相同。
使用 \(mt19937\),用法如下:
mt19937 RND(chrono::steady_clock::now().time_since_epoch().count());
uniform_int_distribution<int>(a, b)(RND);
随机产生 \([a,\ b]\) 中 \(int\)。
shuffle(permutation.begin(), permutation.end(), RND);
random_shuffle() 功能。
代码
#include <bits/stdc++.h>
#ifdef DEBUG
#define debug(...) fprintf(stderr, __VA_ARGS__)
#else
#define debug(...)
#endif
#ifdef __WIN32
#define LLFORMAT "I64"
#else
#define LLFORMAT "ll"
#endif
using namespace std;
long long n;
int k;
bool Q(long long l, long long r) {
printf("%"LLFORMAT"d %"LLFORMAT"d\n", l, r);
fflush(stdout);
static char s[5];
scanf("%s", s);
return (s[0] == 'Y');
}
int main() {
mt19937 RND(chrono::steady_clock::now().time_since_epoch().count());
scanf("%"LLFORMAT"d%d", &n, &k);
long long l = 1, r = n;
for(;;) {
if(r - l >= 50) {
long long mid = l + r >> 1;
if(Q(l, mid)) {
l = max(1ll, l - k);
r = min(n, mid + k);
}
else {
l = max(1ll, mid + 1 - k);
r = min(n, r + k);
}
}
else {
long long p = uniform_int_distribution<int>(0, (int)(r - l))(RND) + l;
if(Q(p, p)) return 0;
l = max(1ll, l - k);
r = min(n, r + k);
}
}
}