Codeforces 1007C Guess two numbers
题目链接
题意:交互,有两个数
a
,
b
a,b
a,b,你需要猜出他们。每次询问
x
,
y
x,y
x,y,回答有四种返回值:
0表示
a
=
x
,
b
=
y
a=x,b=y
a=x,b=y,即猜中。
1表示
x
<
a
x<a
x<a。
2表示
y
<
b
y<b
y<b。
3表示
x
>
a
x>a
x>a或
y
>
b
y>b
y>b。
如果有多种条件同时满足,会返回任意一种。请在600次操作内找出
a
,
b
a,b
a,b。
a
,
b
≤
1
0
18
a,b\le 10^{18}
a,b≤1018
题解:
把题目看做在平面上猜点,1,2操作实际上是把一个图形平行于坐标轴切开,3操作是切掉右上角的一部分。于是会发现,无论如何操作我们都有方案保证图形在任意时刻都阶梯状的。
考虑把阶梯状的图形分成三块,左下角矩形面积为
S
A
S_A
SA,左上角的矩形面积为
S
B
S_B
SB,右下角矩形面积为
S
C
S_C
SC,则分类讨论:
1.
S
B
≤
S
A
+
S
C
S_B\le S_A+S_C
SB≤SA+SC且
S
C
≤
S
A
+
S
B
S_C\le S_A+S_B
SC≤SA+SB,此时在矩形
A
A
A的正中心做一次询问。
2.
S
B
>
S
A
+
S
C
S_B>S_A+S_C
SB>SA+SC,那么在
S
B
S_B
SB与
S
A
S_A
SA的交界处中点做一次询问。
3.
S
C
>
S
A
+
S
B
S_C>S_A+S_B
SC>SA+SB,那么在
S
C
S_C
SC于
S
A
S_A
SA的交界处中点做一次询问。
容易证明,每次1操作至少让图形面积减少
1
4
\frac 14
41,2,3操作要么把图形切成一个矩形(也就是下次操作无论如何都必然减少
1
4
\frac 14
41),要么直接切下图形的
1
4
\frac 14
41。因此最坏复杂度为:
O
(
l
o
g
4
3
(
1
0
18
×
2
)
×
2
)
<
577
O(log_{\frac 43}(10^{18\times 2})\times 2)<577
O(log34(1018×2)×2)<577
可以通过本题(细节好烦啊,可能是我SB写烦了)。
int check(ll x, ll y) {
printf("%lld %lld\n", x, y);
fflush(stdout);
int t; scanf("%d", &t);
return t;
}
int main() {
ll n; scanf("%lld", &n);
ll ya = n, yb = n, yc = 1, xa = n, xb = n, xc = 1;
while (true) {
if (yc > yb) yb = ya, xa = xb;
if (xc > xb) xb = xa, ya = yb;
ll ym = (yc + yb) >> 1, xm = (xc + xb) >> 1;
if ((__int128)(ya - yb) * (xb - xc) > (__int128)(yb - yc) * (xa - xc)) ym = yb;
else if ((__int128)(ya - yc) * (xb - xc) < (__int128)(yb - yc) * (xa - xb)) xm = xb;
int t = check(xm, ym);
if (t == 0) break;
else if (t == 1) xc = xm + 1;
else if (t == 2) yc = ym + 1;
else xb = xm - 1, yb = ym - 1;
if (yc > yb) yb = ya, xa = xb;
if (xc > xb) xb = xa, ya = yb;
if (ya == yb && yb == yc) {
xb = xc;
while (xa > xb) {
ll mid = (xa + xb) >> 1;
int t = check(mid, ya);
if (t == 0) return 0;
else if (t == 1) xb = mid + 1;
else xa = mid - 1;
}
assert(!check(xa, ya));
return 0;
} else if (xa == xb && xb == xc) {
yb = yc;
while (ya > yb) {
ll mid = (ya + yb) >> 1;
int t = check(xa, mid);
if (t == 0) return 0;
else if (t == 2) yb = mid + 1;
else ya = mid - 1;
}
assert(!check(xa, ya));
return 0;
}
}
return 0;
}