2523: [Ctsc2001]聪明的学生
题目大意
有三个人A,B,C头上分别贴着三个正整数,显然对于任意一个人只能看见其他两个人头上的数字。存在两个数的加和等于另一个,这时候询问A是否知道头上贴着什么数字,在询问B,询问C……直到第n次询问一个人回答出来是m。假设这三个人很聪明,都能以最小的询问次数回答出头上的数字(如果可以)。给定多组n,m求所有可能情况。
解题思路
题目中有个很关键的提示:总是头上贴着最大的那个数的人最先猜出自己头上的数。解决这道题目首先要从答案是如何得出入手。假设对方两个人头上是x,y,我一定是x+y或者|x-y|。
因为提示中的性质,如果我是答案一定是x+y。如果我们能在规定步数否定|x-y|,那么x+y肯定成立。
我们可以设计一个三元组(x,y,t),表示当前最大值在t上,右边是x,左边是y,初始时x显然要枚举。询问(x,y,t)的步数为n的状态是否成立,如果x>y,则询问x-y的步数为n-2的状态是否成立,否则询问y-x的步数为n-1的状态是否成立。最后如果x==y&&t==步数那么以上所有状态都成立,因为当x==y,我们就知道最大值肯定不是|x-y|(因为是正整数),并且步数一定要刚刚好。
#include<cstdio>
#include<algorithm>
using namespace std;
int n,m,a,b,c,tot;
struct jz{
int x[3];
bool operator<(const jz&w)const{
if (x[0]==w.x[0]) return x[1]<w.x[1];return x[0]<w.x[0];
}
}ans[30005];
bool check(int x,int y,int t,int s){
while (s>0){
if (x==y) break;
int xx=x,yy=y;
if (x>y) x=yy,y=xx-yy,t=(t+1)%3,s-=2;else x=yy-xx,y=xx,t=(t+2)%3,s-=1;
}
if (x==y) return s==t;
return 0;
}
int main(){
freopen("exam.in","r",stdin);
freopen("exam.out","w",stdout);
while (scanf("%d%d",&n,&m)){
if (n==-1&&m==-1) return 0;
tot=0;n--;a=n%3;b=(a+1)%3;c=(b+1)%3;
for (int i=1;i<m;i++) if (check(i,m-i,a,n)) ans[++tot].x[a]=m,ans[tot].x[b]=i,ans[tot].x[c]=m-i;
sort(ans+1,ans+1+tot);
printf("%d\n",tot);
for (int i=1;i<=tot;i++) printf("%d %d %d\n",ans[i].x[0],ans[i].x[1],ans[i].x[2]);
}
}