首页 > 其他分享 >鬼谷子猜数

鬼谷子猜数

时间:2023-03-29 21:11:06浏览次数:33  
标签:两个 乘积 猜数 53 孙膑 鬼谷子 知道

很久之前写的,搬过来。

一个与OI本身并木有什么联系的问题,只是感觉很有趣而且验证过程用到了计算机(主要是懒得手算),便花一点点时间来写一下。

问题

一天,鬼谷子随意从2-99中选取了两个数。他把这两个数的和告诉了庞涓,把这两个数的乘积告诉了孙膑。但孙膑和庞涓彼此不知道对方得到的数。第二天,庞涓很有自信的对孙膑说:“虽然我不知道这两个数是什么,但我知道你一定也不知道。”随后,孙膑说:“那我知道了。”接着庞涓说:“那我也知道了”。

请问这两个数是什么?

解法

看似很无厘头的对话,但这个问题确实有解。世界真奇妙。

接下来让咱们一句句分析:

  • 庞涓:“我不知道这两个数是什么”

这句话……跳过。其实它也不是没有蕴含信息(这句话表明庞涓得到的数不是2、3或197、198),但信息实在太少了。不管它就行了。

  • 庞涓:“但我知道你不知道”

翻译一下就是,庞涓肯定自己的数不存在一种分解使得它们的乘积告诉孙膑之后他能立马猜出这两个数。

首先第一步,我们可以反向思考,孙膑得到哪些数之后,能立马猜出来?

一种可能是它是两个质数的乘积,原因显而易见。另一种是这个数是53与另外一个数的乘积,因为这样的乘积也都只有一种分法(53\(\times ?\)),毕竟只要再分给53一个因子第一个乘数就超范围了。

整理一下,庞涓拿到的数不会大于54(因为保不准鬼谷子想到的数就有53),也不会能等于两个质数之和。那……都有哪些数?

上代码。其中check函数为判断是否为质数的函数。

for(int i=4;i<=54;i++){
	bool ok=true;
	for(int j=2;j<=i/2;j++)
		if(check(j)&&check(i-j)){ok=false;break;}
	if(ok)printf("%d ",i);
}

输出:11 17 23 27 29 35 37 41 47 51 53

  • 孙膑:“那我知道了”

没错我们的懂王听完庞涓的话之后懂了。这句话说明什么?首先要明确一点,既然到这一步为止我们已经推断出庞涓手上可能的数有哪些,那么机智过人的孙膑肯定也早就得出了这个数列。而他懂了,说明他手上的数分解后所有可能的两数之和有且只有一个在上述集合之中。

很绕,非常绕。但确实求得出来有哪些可能的值。代码中A数组记录了上面得到的11个数,下标从1开始。

for(int i=1;i<=11;i++){
	for(int j=2;j<=A[i]/2;j++){
		num[j*(A[i]-j)]++;
	}
}
for(int i=1;i<1000;i++)if(num[i]==1)printf("%d ",i);

输出(后面的输出不重要)18 24 28 50 52 54 76 92 ......

  • 庞统:“那我也知道了”

没错我们的另一个懂王听完孙膑的话之后也懂了(tmd就你们最懂)。这说明什么?套用刚才的分析方法,我们可以知道,庞统应该也得到上面我们输出的那一长串数了。而庞统现在懂了,说明什么?说明他手上的数只有一种方法可以拆分为两个数使得这两个数的乘积在上面的那个集合之中。接下来的事情不就好办了吗,枚举就行了啊……

代码是在上一步的基础上完成的。

for(int i=1;i<=11;i++){
	for(int j=2;j<=A[i]/2;j++){
		num[j*(A[i]-j)]++;//代表此乘积的方案数加一 
		fr[j*(A[i]-j)]=i;//记录这个乘积是由哪个和转移过来的 
	}
}
for(int i=1;i<1000;i++){
	if(num[i]==1){//如果当前i在上一步得到的那个奇怪的集合中 
		use[fr[i]]++;//记录这个和可能的种数 
		one[fr[i]]=i;//顺便记录一下从哪里来的 
	}
}
for(int i=1;i<=11;i++){
	if(use[i]==1){//如果这个和只有一种分解方法说明他是正解 
		printf("%d %d",A[i],one[i]);
		//注意此时输出的是鬼谷子想的两个数的和与积 
	}
}

输出17 52

没错,只有一种可能。

  • 最后一步

问题变成了已知两个数的和与两个数的积,求这两个数。这就有点侮辱人了对吧。显然可以求出这两个数分别是13和4。然后就完了。

当时是在一个奇怪的CSP-J初赛中做到的这道题,当时顿时怀疑人生(好家伙入门组都这么难那还玩个鬼),下来之后看网上各种题解,发现其中使用各种各样的分析技巧和数论知识本蒟蒻都不会,便想到能否用其它方法来搞定这道题。于是,学过\(10^{-43}\)秒信竞的我决定秉承着“暴力出奇迹打表拿省一”的精神暴力枚举(其实数据规模也不大),没想到真的枚举出来了。特写此文纪念。

原创不易哦(你应该知道我想说啥吧)。

标签:两个,乘积,猜数,53,孙膑,鬼谷子,知道
From: https://www.cnblogs.com/Feyn/p/17270340.html

相关文章

  • Python猜数字游戏(4版)
    前言这是我的一次python实验,记录一下正文1.基础版在程序中预设一个0-9之间的整数,让用户通过键盘输入所猜的数,如果大于预设的数,显示“你猜的数字大于正确答案”;小于预设的数,......
  • 猜数字小游戏
    这是python课上写的一个小游戏,其实就是一个猜数字的游戏这是while循环的形式 这是for循环 try...except是用来判断输入的是不是数字,如果不是就会提示并重新接收,下面就......
  • 决战鬼谷子
    43C86955C14C9849599206545ED811F4#张三43C86955C14C9849599206545ED811F31#李四43C86955C14C9849599206545ED811F42#王五43C86955C14C9849599206545ED811F33#赵六43C8......
  • 随机猜数小游戏
    #include<stdio.h>#include<time.h>#include<stdlib.h>intgame(intx){intr=0;r=rand()%100+1;while(1){printf("请输入你想要猜的数值:\n");scanf_s(......
  • 【C语言】猜数字小游戏「功能优化」
    ......
  • HDOJ2178 猜数字
    题目链接​​:http://acm.hdu.edu.cn/showproblem.php?pid=2178​​题目的意思比较难以理解。讲的是"最多猜n次,但一定可以猜到1至m(闭区间[1,m])内的任意数字,求m的最大值......
  • C++ 猜数字
    #include<iostream>#include<random>#include<limits>namespacerandom{std::random_devicerd;std::seed_seqrr={rd(),rd(),rd(),rd(),rd(),rd......
  • 3604、猜数字大小
    猜数字游戏的规则如下:每轮游戏,我都会从1到n随机选择一个数字。请你猜选出的是哪个数字。如果你猜错了,我会告诉你,你猜测的数字比我选出的数字是大了还是小了。你可以通......
  • 关于“猜数游戏”的反思 与分析理解
    [USACO08JAN]HaybaleGuessingG题面翻译给一个长度为\(n\)的数组\(q\)个条件,数组中的数字互不相同,每个条件格式形如\(l_i,r_i,x_i\)表示这个数组的区间\([l_i,r......
  • C语言-猜数游戏
    整理文件发现以前写的C语言猜数游戏1-效果演示2-程序#include<stdio.h>#include<stdlib.h>#include<time.h>intmain(){ srand(time(0)); intnumber=rand......