BZOJ 2523: [Ctsc2001]聪明的学生

Description

一位教授逻辑学的教授有三名非常善于推理且精于心算的学生A,B和C。有一天,教授给他们三人出了一道题:教授在每个人脑门上贴了一张纸条并告诉他们,每个人的纸条上都写了一个正整数,且某两个数的和等于第三个。于是,每个学生都能看见贴在另外两个同学头上的整数,但却看不见自己的数。

这时,教授先对学生A发问了:“你能猜出自己的数吗?”A回答:“不能。”
教授又转身问学生B:“你能猜出自己的数吗?”B想了想,也回答:“不能。”
教授再问学生C同样的问题,C思考了片刻后,摇了摇头:“不能”。
接着,教授又重新问A同样的问题,再问B和C,……,经过若干轮的提问之后,当教授再次询问某人时,此人突然露出了得意的笑容,把贴在自己头上的那个数准确无误的报了出来。

现在,如果告诉你:教授在第N次提问时,轮到回答问题的那个人猜出了贴在自己头上的数是M,你能推断出另外两个学生的头上贴的是什么数吗?

[提示]
在没有人猜出自己头上的数之前,大家对教授提问的回答始终都是“不能”;而且除此之外在A,B,C之间是没有进行任何信息交流的。也就是说,每个人推断的依据仅仅是另外两个人的头上数,以及大家对教授的提问所做出的否定回答。
教授总是从学生A开始提问的。
你可以假定,这三个足够聪明的学生能够根据已知的条件在最早的轮次猜出自己的数,并且永远都不会猜错。
稍经分析和推理,你将得出以下结论:总是头上贴着最大的那个数的人最先猜出自己头上的数。

Input

包括若干组测试数据,其中的每一行代表一组测试数据,由两个整数N和M组成(即在教授第N次提问时,轮到回答问题的那个人猜出了贴在自己头上的数是M)。两个数之间用空格分隔开。最后,由-1 -1组成的一行标志着输入数据的结束。
0

Output

按照输入文件中的顺序依次给出各组数据的结果。
文件中对应每组数据的输出的第一行是一个整数p,是可能情况的总数。接下来的p行,每一行包括三个数,分别为贴在A,B,C头上的三个数。输出时,所有解按照A头上的数增序排列;在A头上的数相同的情况下,按照B头上的数增序排列。

Sample Input

5 8

3 2

2 3

-1  -1

Sample Output

3

2 8 6

5 8 3

6 8 2

1

1 1 2

1

2 3 1

分析

这题特别的有趣。其实这是一个很有趣的数学问题的弱化版,原来的那个问题我记不太清了,但是我记得有另外一个弱化的版本,是数学归纳悖论。其实这一类的问题有好多种说法的,我这里找了一种。

有一个与世隔离的小岛,上面住着一个暴君,他有100个奴隶。暴君为了展示“宽容”,他给每个奴隶带上一个帽子,只要猜出帽子的颜色,就可以在每天凌晨选择离开,但是如果猜错,就要砍头。有以下2个前提:

1,奴隶之间不能交流。

2,帽子只有2种颜色绿色和黄色。

然而其实暴君给每个人带上都是绿色帽子。

暴君正在为自己的智商而高兴时,突然有一个社会学家要来岛上访问,暴君碍于外交,答应了,但是也给出了条件,如果社会学家透露了重要的条件,就不客气了。

社会学家其实是个大数学家,他来岛上就说了一句话:

3,你们奴隶中至少有一个人带的是绿帽子。

暴君觉得没啥~社会学家就安全的回去了。

但是神奇的事情发生了,1-99天没人离开,100天后,100奴隶集体准确说出自己的绿色帽子,安全离开。

至于推导过程十分的简单,在此就不赘述了

那么说回到这道题目对于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)枚举每一种情况,得到答案。

代码

#include <algorithm>
#include <iostream>
#include <cstring>
#include <complex>
#include <cstdio>
#include <queue>
#include <cmath>
#include <map>
#include <set>

#define N 10000
#define INF 0x7fffffff
#define sqr(x) ((x) * (x))
#define pi acos(-1)

int n,m,k;
int cnt;

int ans;
int a,b,c;

int out[3][N];

int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9'){if (ch == '-') f = -1; ch = getchar();}
    while (ch >= '0' && ch <= '9')  {x = x * 10 + ch - '0'; ch = getchar();}
    return x * f;
}

int dfs(int x,int y,int z,int tot,int sum)
{
    if (sum > n)
        return 100;
    if (tot == 0)
        tot = 3;
    if (y ==z)
        return tot;
    return dfs(y, z, abs(y - z), tot - 1, sum + 1) + 1;
}

void slove(int x,int y,int z)
{
    if (k == 1)
        ans = dfs(x, z, y, 1, 0);
    else
        if (k == 2)
            ans = dfs(x, y, z, 2, 0);
        else ans = dfs(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) && n != -1 && 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++)
            slove(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]);
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值