D. Ehab and another another xor problem (异或)交互

本文解析了一种基于二进制位操作的互动算法,用于猜测未知的两个整数a和b的值。通过巧妙地设计提问策略,利用62次询问机会,逐位确定目标数值,最终准确猜出a和b。文章详细介绍了算法思路,包括如何通过对比问询结果判断二进制位的值,以及如何处理交互式输出的刷新问题。

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

题目链接:哆啦A梦传送门

题意:让你猜猜题目背后的a,b的值,可以问一些问题给题目,它会回答你问题,最多不超过62次提问,a,b不超过 2^30,

问问题的方式 ?c d ,然后题目会计算a^c-b^d,大于0,返回1,等于0,返回0,小于0,返回-1,当你可以猜出结果时,输出!a b。

 

题解:看到a b二进制为不超过30位,然后题目又给你62次问询,显然是有特定的问询,可以把a b二进制位每位按顺序找出来,关键是我们怎么问询以及怎么判断此位是0还是1。赛后看了官方标程,自己模拟了几组,得出了问询方式以及怎么判断此位是0还是1。

首先,我们从最高位(30)开始一直找到最低位,a b二进制位也就四种情况:

(1,1) (0,0) (1,0) (0,1)

问询方式,我们将原a b二进制位,分别单个取反,得出结果来,判断结果,具体见代码注释。

看完之后,举几个例子,例如:

1010  0101

从最高位开始,因为都是0,故f=1(左单取反1...1010 ,0...0101),s=-1(右单取反 0...1010,1...0101),故不满足判断条件,下一位

一直到第三位 ,f=-1(左单取反0...0010 ,0...0101),s=-1(右单取反 0...1010,1...1101),两值相等,故为(1,0)或(0,1)

因为big=1,big表示下一次位为(1,0)或(0,1)时,谁比较大,谁大就加到谁头上,那么此时big=-1,表示下一组位为(1,0)或(0,1)时,b比较大,要加到b头上。

再给两个:

1111  0111 和 1110 0111,自己模拟下,就会更理解得透彻。

 

这题还有个交互的考点,每次输出时,如果是printf输出的话,要在这之后加一句fflush(stdout)cout<<flush();如果是cout的话,要加cout<<endl(endl有自动刷新缓冲池的功能);加这些语句的意思是,频繁循环输出,和 频繁循环交替输入输出 情况下,会不及时输出,而是等到缓冲区有一定数量内容时再输出。这种情况下,才用endl 或 flush 迫使 程序及时输出

#include <iostream>
using namespace std;
int ask(int c,int d)
{
	cout << "? " << c << ' ' << d << endl;
	int ans;
	cin >> ans;
	return ans;
}
int main()
{
	cout.flush();
	int a=0,b=0,big=ask(0,0);///big的作用是,判断是否是(1,0),(0,1)时,原a b是否谁大
	for (int i=29;i>=0;i--)
	{
		int f=ask(a^(1<<i),b),s=ask(a,b^(1<<i));///单个取反
		
		if (f==s) ///相等说明 此位原a b为1 0或 0 1
		{
			if (big==1) ///谁大给谁当前位赋值为1
			a^=(1<<i);
			else if(big==-1) ///big等于0不出出现在这里判断,因为big=0的话,即这后面的每位都相等,故不会出现在此if语句
			b^=(1<<i);
			big=f;
		}
		else if (f==-1) ///此位原a b都为1,
		{
			a^=(1<<i);
			b^=(1<<i);
		}
		///假如此位原a b为0,故f=1,s=-1,跳过,下一个位判断
	}
	cout << "! " << a << ' ' << b << endl;
}

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值