BZOJ 2523 [Ctsc2001]聪明的学生

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]);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值