Codeforces 1007C Guess two numbers [二分+思维]

本文详细解析了Codeforces 1007C问题,通过将问题转换为平面猜点游戏,利用交互式算法在600次操作内猜测两个未知数。通过巧妙地划分图形区域并进行分类讨论,确保每次操作都能有效缩小搜索范围,最终实现高效求解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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 &lt; a x&lt;a x<a
2表示 y &lt; b y&lt;b y<b
3表示 x &gt; a x&gt;a x>a y &gt; b y&gt;b y>b
如果有多种条件同时满足,会返回任意一种。请在600次操作内找出 a , b a,b a,b
a , b ≤ 1 0 18 a,b\le 10^{18} a,b1018

题解:

把题目看做在平面上猜点,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 SBSA+SC S C ≤ S A + S B S_C\le S_A+S_B SCSA+SB,此时在矩形 A A A的正中心做一次询问。
2. S B &gt; S A + S C S_B&gt;S_A+S_C SB>SA+SC,那么在 S B S_B SB S A S_A SA的交界处中点做一次询问。
3. S C &gt; S A + S B S_C&gt;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 ) &lt; 577 O(log_{\frac 43}(10^{18\times 2})\times 2)&lt;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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值