本期周赛几乎忘记参加,在最后几分钟的时候上来看了看。那些选择判断一通乱选,填空题也已经被吐槽得差不多了,这里不多说,只说我对第一道编程题的看法(吐槽)。因为 C 站的机制是,即使它错了,它也不会承认(印象里只承认且改过一次),再争辩只会把你拉黑,甚至限流也有可能,所以只能把我的观点放在博客里,不再专门去反馈了。
先来看题目:
给定一组n个正整数,要求每次选其中一个数乘以或除以一个素数(称为一次凑数),问至少需要凑数多少次可以把所有的数都凑成相等。
输入描述:
第一行输入n个正整数(0<n<=1000000,其中每个数都小于1000000)。
输出描述:
可以把所有的数都凑成相等需要至少进行的凑数次数t(t>=0)。
输入样例:
5 20
输出样例:
2
我的观点是:这是道好题——好题在我这里的定义是,大部分人的解读是错的。而且至少目前来看,还没发现有人说对了。甚至我有九成的把握,此题测试用例的“标准答案”也是错的,剩下一成留给出题人来“深度解读”题意。
我认为此题关于“凑数”的定义是没有歧义的:
- 每次选其中一个数
- 将其乘以或除以一个素数(质数)
同时满足上面两点即称为“一次凑数”,注意黑体加粗的“或”字。而将所有数字通过凑数变成相等的目标数字,却是没有确定的。
所以根据上述规则,对于给出的样例的两个数字 5 和 20 来说,有三种最优的方式(两次凑数)将其变成相等。
- ,
只有两个数字时,找出这样的目标数字并不难——肉眼可见,前两种方法分别是最小公倍数和最大公约数。但能不能把这种规律扩展到三个数字以上呢?相信很多人的第一反应也是这样做的(通过测试用例的答案来看,感觉出题人可能也是这样想的)。但是很遗憾,由于“凑数”的定义是“其中一个数“”可以“乘以或除以”,并没有规定所有数都只能乘以或除以,所以存在第三种情况,即当某一部分的数字乘以一个素数,另一部分的数字除以一个素数的时候,也就是说,将所有数字变成一个最小公倍数和最大公约数之间的中间数字的时候,总的操作数更少。
举个简单的例子:2, 4, 8 。这三个数字的最小公倍数是 8, 最大公约数是 2,但是如果将三个数字都变成 8 或 2,都需要 3 次凑数:
但是如果把三个数字都变成 4,只需要 2 次凑数:
所以,我们不能通过找最小公倍数或最大公约数,找到最优的凑数方案。
那该怎么做呢?
我们知道,任何正整数都可以进行质因数分解,写成 的形式。其中 表示所有素数, 。
而将所有整数都变成一个相等的目标数字,等价于将所有整数的质因数排列形式变成一致。其中,整数里原本没有的质数,就要加上(乘以),原本多出来的质数,就要减少(除以),最终使得所有数字包含的每个质数的个数都各自相同。而相信你也看出来了,这里的“加上”和“减少”操作,其实就是本题所定义的“凑数”。
用公式来说明,假如有三个整数 ,分别可以写成
而我们想要凑成的最终数字,应该是
其中, 各自通过加减,统统变成 , 各自通过加减,统统变成 , 各自通过加减,统统变成 。不难看出,本题所要找的“凑数次数”,就是上面这些质数原本的个数变成最终个数,所需要的加或减的次数之和。而要使这个“次数之和”最小,每个质数原本的个数到最终个数的距离之和就必须最小。
所以,问题的关键变成了如何找出每个质数的“最终个数”。
相信有点数学基础的同学,很容易就能发现:在一群数中间找到一个数,使得所有数字到这个数字的距离之和最小,那么这个数必然是这群数字的中位数。——实际上,这也是中位数用处最广的特性之一。
到此,解题方法呼之欲出了。只需下面三步:
- 将所有整数进行质因数分解,找出所有质数的个数
- 将这些质数的个数分别进行排序,找到每个质数个数的中位数(没有该质数的整数相应的个数记为 0,参与排序)
- 累加每个质数到其中位数的个数之差。
相关代码放在某个地方了,这里就不重复了 :D
但是很遗憾,虽然我自信这种做法是正确的,但却通不过 C 站的测试。——这也是为什么我说九成认定 C 站的答案错了。
以彼之矛攻彼之盾,我们用 C 站本题自己的用例来打脸它。
本题有一组相对数量较少的用例如下:
标准答案是 38。也就是说 C 站认为最少需要 38 次凑数才能将所有数字变成相等。
虽然我不知道 C 站认为的最终相等的数字是多少,但我知道将所有数字都变成 1,是需要 38 次的,所以可以拿来进行分析和比较。具体如下:
虽然本例有点变态(出现了6位质数),但万变不离其宗,用我们前面介绍的方法进行分析,甚至通过肉眼就可以发现,这里有八个偶数,只有两个奇数,很显然将两个奇数乘以 2,要比将八个偶数除以 2,次数更少。
所以,我认为的正确答案应该是 32 次,也就是将所有数字变成 2,仅需要 32 次凑数:
至于如何通过 C 站本题的测试,我也早已有了答案,只是对于这种题意和答案不符的情况,还是不吐(槽)不快。
好了,是非对错,有缘读到这里的读者自己判断吧。
也欢迎有人提出反对意见,毕竟胜负终归浮云,唯有真理越辩越明。