原谅我逻辑能力差
首先看到题目的提示:稍经分析和推理,你将得出以下结论:总是头上贴着最大的那个数的人最先猜出自己头上的数。
然而怎么证?!
对于A,如果B,C数字相同,他可以立刻得知它头上的是B+C。否则有两种可能:B+C或|B-C|。不妨设A>B>C,A=B+C,经过n次询问,A可以猜出。那么对于A,A+C,C,经过n+1次询问,B认为如果他是A-C,A应当在n次询问时得出答案,因此他不是|A-C|,他可以得出他是最大的。
假设刚才的证明没有问题,设A>B>C,A假设他自己是|B-C|,那么上一轮C不是最大,无法推断,在上一轮B最大,他会假设他是|A-C|,那么上一轮A……直到某个人看到另外2人一样。因为询问从A开始所以还要倒推至A,然后你会发现这是正确的。这样我们可以在O(n)时间内判断某组数字能否在正好n次询问时解决
已知n次询问,最大的是m,O(nm)枚举每一种情况,得到答案。
(work()中的x是不必要的,可以删除)
#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;
int n,m,k,cnt,Out[3][10000],Ans,a,b,c;
int work(int x,int y,int z,int t,int sum)
{
if (sum>n) return 100;
if (t==0) t=3;
if (y==z) return t;
return work(y,z,abs(y-z),t-1,sum+1)+1;
}
void doit(int x,int y,int z)
{
if (k==1) Ans=work(x,z,y,1,0);
else if (k==2) Ans=work(x,y,z,2,0);
else Ans=work(x,z,y,3,0);
if (Ans==n)
{
cnt++;Out[a][cnt]=x;Out[b][cnt]=y;Out[c][cnt]=z;
}
}
int main()
{
while(scanf("%d%d",&n,&m)&&m!=-1)
{
k=n%3;cnt=0;
if (k==1) a=0,b=1,c=2;
else if (k==2) a=1,b=0,c=2;
else a=2,b=0,c=1;
for (int i=1;i<m;i++)
doit(m,i,m-i);
printf("%d\n",cnt);
for (int i=1;i<=cnt;i++) printf("%d %d %d\n",Out[0][i],Out[1][i],Out[2][i]);
}
}