P8541 「Wdoi-2」死亡之后愈发愉悦
P8541 「Wdoi-2」死亡之后愈发愉悦
二分未知上界的数的最好方式是倍增。
考察两个相邻的完全平方数
设
因此,考虑倍增求出使得
倍增方法:依次尝试以
询问次数为
实际上我们发现
代码和题解有一些细节上的差异。
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
using namespace std;
using namespace __gnu_pbds;
#define int long long
#define fi first
#define se second
#define TIME 1e3 * clock() / CLOCKS_PER_SEC
using ll = long long;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
using ull = unsigned long long;
inline ll read() {
ll x = 0, sgn = 0;
char s = getchar();
while(!isdigit(s)) sgn |= s == '-', s = getchar();
while(isdigit(s)) x = x * 10 + s - '0', s = getchar();
return sgn ? -x : x;
}
inline void print(int x) {
if(x < 0) return putchar('-'), print(-x);
if(x >= 10) print(x / 10);
putchar(x % 10 + '0');
}
bool Mbe;
map<int, bool> mp;
int query(int x) {
if(mp.find(x) != mp.end()) return mp[x];
cout << "? " << x << endl;
int res = read();
return mp[x] = res;
}
int suc(int x, int acc) {
int st = query(x);
if(query(x + 1) != st) return x;
int pw = 0;
while((1 << pw + 1) <= acc) pw++;
while(1) {
if(query(x + acc + (1 << pw)) != st) break;
acc += 1 << pw, pw++;
}
for(int i = pw - 1; ~i; i--)
if(query(x + acc + (1 << i)) == st)
acc += 1 << i;
return x + acc;
}
bool Med;
signed main() {
fprintf(stderr, "%.3lf MB\n", (&Mbe - &Med) / 1048576.0);
// #ifdef ALEX_WEI
// FILE* IN = freopen("1.in", "r", stdin);
// FILE* OUT = freopen("1.out", "w", stdout);
// #endif
int T;
cin >> T;
while(T--) {
mp.clear();
int p = suc(0, 1);
int q = suc(p + 1, max(1ll, p - 1)) - p;
if(!query(0)) cout << "! " << (q - 1) * (q - 1) - 1 - p << endl;
else cout << "! " << q * (q + 1) - p << endl;
}
cerr << TIME << " ms\n";
return 0;
}