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

版权声明:转载注明下出处就行了。 https://blog.csdn.net/LJD201724114126/article/details/84845564

题目链接:哆啦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;
}

猜你喜欢

转载自blog.csdn.net/LJD201724114126/article/details/84845564