一只猩猩离家 50 米, 身边有 100 根香蕉. 如果猩猩每次最多携带 50 根香蕉, 且每移动一米都消耗一根香蕉, 问猩猩最多能把多少根香蕉带到家?

我们的方案如下: 第一步, 让猩猩携带 50 根香蕉前进 x 米, 放下尽可能多的香蕉后原路返回. 依题意, 最多在 x 米处放 50-2x 根香蕉.
第二步, 让猩猩携带剩下的 50 根香蕉, 连同在 `x` 米处暂存的香蕉一起带回家. 这一段路共消耗 50 根香蕉, 所以带回家的香蕉有 50-2x 根. 注意在 x 米处猩猩携带的香蕉不能超过 50 根, 所以 (50-2x) + (50-x) ≤ 50, 令 y = 50-2x, 从上式解得 y ≤ 50/3, 即 y ≤ 16.

若多面体表面只由正五边形和正六边形组成, 则五边形的个数一定是 12 (如, 正十二面体或足球).

设有 `x` 个五边形, `y` 个六边形, 又设该多面体的顶点数为 `V`, 棱数为 `E`, 面数为 `F`. 我们有 `F = x + y`, `quad 2E = 5x + 6y`. 因为正五边形和正六边形的内角均大于直角, 所以每个顶点处恰有三个面相交, 即 `2E = 3V`. 最后, 再和 Euler 公式 `V - E + F - 2 = 0` 联立, 得到 `x = 12`, `quad y = V/2 - 10`.

    海盗分金 5 个海盗抢得 100 枚金币后讨论分赃. 他们抽签确定每人的排序 (1, 2, 3, 4, 5), 然后, 从 1 号开始提出分配方案 `(x_1, x_2, x_3, x_4, x_5)`, 其中 `Sigma x_i = 100`. 这方案由在场所有人 (包括提出者) 表决, 若同意的人数过半 ( 严格 > ), 就按此方案分配; 否则将提出者扔进大海喂鲨鱼. 若 1 号被扔进大海, 则由 2 号提出方案并由剩余在场的人按同样的规则表决. 依此类推. 我们假设
  1. 每个海盗绝对理性, 即他们考虑的优先级都是 自己的生命 > 尽可能多的金钱 > 在生命得到保障, 并获得同样金钱的前提下, 尽可能减少同伙的数量.
  2. 海盗都严格按照以上描述的规则进行分金, 且每一轮表决的结果都能顺利执行.
  3. 那么, 1 号海盗应该提出怎样的最优方案?
    考虑 `n` 个海盗, `m` 枚金币的分金问题, 注意到 1 号被扔进大海后, 这个问题就转换为 `n-1` 个海盗, `m` 枚金币. 因此把所有海盗按提出方案的次序反向编号为 `p_n, p_(n-1), cdots, p_1, p_1` (p 是 pirates 的首字母). 记这时 1 号, 即 `p_n` 所提的方案为 `P(n) = (c_1, c_2, cdots, c_(n-1))`, (P 是 Proposal 的首字母, c 是 coin 的首字母) 剩下的金币就全归 `p_n`. 我们从较小的 `n` 开始考虑.
  1. `n = 2` 时, 显然 `p_1` 总能否决 `p_2` 的方案并把他扔进大海. 这是 `p_2` 要极力避免的情形.
  2. `n = 3` 时, 不论 `p_3` 提出什么方案, `p_2` 都要支持他. 此时 `P(3) = (0, 0)`.
  3. `n = 4` 时, 除了 `p_4` 自己, 还需要两个拥护者来巩固自己的地位. 只要开出比 `P(3)` 更高的价钱, `p_1, p_2` 是乐意支持的. 此时 `P(4) = (1, 1, 0)`.
  4. `n = 5` 时, 同样需要拉拢两名拥护者, `P(5) = (2, 0, 1, 0)` 或 `(0, 2, 1, 0)`

教授与三学生 教授在他的三个学生每人脑门上贴了纸条, 告诉他们, 每人的纸条上写着一个正整数, 其中一个数是另外两数之和. 这三个学生均非常聪明, 每人可以看见其他两人的数字, 但看不见自己的. 教授问第一个学生: 你能猜出自己的数吗? 答不能. 问第二个, 答不能. 问第三个, 答不能. 再问第一个, 答不能. 再问第二个, 答不能. 再问第三个, 答 144. 教授满意地笑了. 请问另外两人的数字是多少?

设三个人为 A, B, C, 对应数字为 `a, b, c`.
事件 情报
开始 `a, b, c != 0`, 每人的数字是其他两人数字的和或差
A 说: 不能 `b/c != 1/1`, 否则由 `a != 0` 知 `a != b-c`, 那么 `a = b+c`.
B 说: 不能 `a/c !in {1/1, 2/1}`, `a/c != 2` 是因为, 否则由 `b != c = a - c` 推出 `b = a + c`.
C 说: 不能 `a/b !in {1/1, 1/2, 2/1, 2/3}`, 推理类似.
A 说: 不能 `b/c !in {1/2, 2/1, 2/3, 1/3, 3/1, 3/5}`
B 说: 不能 `a/c !in {1/2, 3/2, 3/1, 1/3, 5/3, 2/3, 4/3, 4/1, 2/5, 8/5}`
C 说: 144 `a/b in {1/3, 3/1, 3/5, 3/2, 3/4, 1/4, 5/2, 5/8, 2/5, 4/1, 4/7, 4/3, 4/5, 2/7, 8/3, 8/13}`
结合 `144 = 2^4 * 3^2` 得 `a:b:c in {1:3:4, 3:1:4, 3:5:8, 4:5:9, 2:7:9}`, 即 `(a, b) in {(36, 108), (108, 36), (54, 90), (64, 80), (32, 112)}`.

和先生与积先生 有两个正整数 x, y, 满足 1 < x < y, 且 x+y < 100. 数学家“和先生”知道这两个数的和,数学家“积先生”知道这两个数的积,他们进行了如下对话:
积先生: 我不知道 x 和 y 分别是啥.
和先生: 我知道你不知道.
积先生: 我现在知道了.
和先生: 如果你知道了, 那我也知道了.
那么, x 和 y 各是多少?

    从公共知识出发, 按步骤推理:
  1. 从初始条件推出, 两数乘积必是合数, 且不是平方数. 两数和至少是 2+3=5, 至多是 49+50=99.
  2. 积先生不知道, 从而 x, y 不全为素数.
  3. 和先生知道积先生不知道, 由哥德巴赫猜想 (x), 两数和不能是偶数, 也不能是 p+2, 其中 p 为奇素数. 可能的两数和只有 A = {11, 17, 23, 27, 29, 35, 37, 41, 47, 51, 53, 57, 59, 65, 67, 71, 77, 79, 83, 87, 89, 93, 95, 97}. 此外, 两数和也不能是 2p+q, 其中 p, q 是素数, q ≥ 53. 这是因为如果两个数正好是 2p 与 q, 那么积先生会发现, 乘积 2pq 不能分解为 2q 与 p, 因为 2q+p > 100. 2pq 更不能分解为 2 与 pq, 因为 2+pq > 100. 这一步直接将 ≥ 57 的两数和全部排除, 现在可能的两数和有 B = {11, 17, 23, 27, 29, 35, 37, 41, 47, 51, 53}.
  4. 积先生知道了, 这说明乘积 xy 有多个非平凡分解, 但只有一个分解使得两数和属于集合 B. 特别地, 如果乘积形如 2ⁿp, 其中 n ≥ 2, p 是奇素数, 那么它只有一个分解 2ⁿ+p 满足两数和为奇数的条件. 我们先假设乘积形如 2ⁿp, 且 2ⁿ+p∈B.
  5. 逐个考虑元素 b∈B, 将它写成 b = 2ⁿ+p 的形式. 如果有不止一种写法, 那么和先生在最后一步无法确定 x, y 的值, 则这个数 b 应当排除掉. 事实上
    11 = 4+7 = 8+3,
    17 = 4+13,
    23 = 4+19 = 16+7,
    27 = 4+23 = 8+19 = 16+11,
    29 = 16+13,
    35 = 4+31 = 16+19 = 32+3,
    37 = 8+29 = 32+5,
    41 = 4+37,
    47 = 4+43 = 16+31,
    51 = 4+47 = 8+43 = 32+19,
    53 = 16+37.
    
    经过排除, 剩下的可能的两数和是 C = {17, 29, 41, 53}.
  6. 逐个考虑元素 c∈C, 将它写成两数和 c = x+y 的形式, 其中 1 < x < y. 并且乘积 xy 满足: 有多个非平凡分解, 但只有一个分解使得两数和属于集合 B. 如果这样的 c = x+y 有不止一种写法, 那么这个 c 应当排除掉. 事实上集合 C 中仅有 17 的写法是唯一的:
    17 = 4+13
    29 = 16+13 = 4+25 = ... // 100 分解为偶数乘奇数有 100 = 4*25 = 20*5, 但 20+5 ∉ B.
    41 = 4+37 = 16+25 = ... // 400 = 16*25 = 80*5, 但 80+5 ∉ B.
    53 = 16+37 = 32+21 = ... // 672 = 32*21 = 96*7 = 224*3, 但只有 32+21∈B.
    
    用下面的暴力程序寻找 c 的合法分解. 只有 find(17) 输出了唯一解.
    
    # 枚举 n 的非平凡分解
    def factors(n):
        res = []
        for i in range(2, int(sqrt(n))+1):
            if n % i == 0:
                res.append([i, n//i])
        return res
    
    B = [11, 17, 23, 27, 29, 35, 37, 41, 47, 51, 53]
    def find(c):
        # 枚举 x+y = c
        for y in range(c//2+1, c-1):
            x = c - y
            flag = True
            # 枚举 x*y 的分解
            for a, b in factors(x * y):
                # c 已经在 B 中, 我们跳过它
                # 一旦发现另一个分解使两数和属于 B
                # 那么乘积 xy 不是我们要找的
                if a+b != c and (a+b) in B:
                    flag = False
                    break
            # 打印合法分解
            if flag:
                print(x, y)
    
  7. 结论: x = 4, y = 13.

狗妈妈送肉

称硬币 [bilibili@Solara570] `n` 枚硬币中, 有 0 或 1 枚假币. 真币的重量都相同, 而假币比真币偏重或偏轻. 如何利用一台无砝码的天平, 在最坏的情况下, 用最少的步数找出假币, 并确定它是偏轻还是偏重?

  1. 给硬币编号 `1` 到 `n`, 设 `i` 号硬币的重量是 `x_i`. 每次称量后, 获得一个不等式. 比如把 `1, 2, 3` 号硬币放在左盘, `4, 5, 6` 号放在右盘, 而右盘更重的话, 就有 `x_1 + x_2 + x_3 lt x_4 + x_5 + x_6`. 由于至多有一枚假币, 而其他真币的重量都相同, 我们可以适当选取重量单位, 使得假币与真币的重量之差为 1. 只要保证天平两边硬币数目相同, 就可以将不等式统一处理为等式, 形如 `sum_(i=1)^n a_i x_i = b_i`. 其中 `a_i` 的取值是 `b_i` 的取值是 `m` 次称量后, 得到一个 `m` 行 `n` 列矩阵 `bm A` 和线性方程组 `bm A bm x = bm b`. 其中 `bm A = (a_(i j))`, `bm x = (x_1, cdots, x_n)^(sf T)`, `bm b = (b_1, cdots, b_m)^(sf T)`. 列向量 `bm x` 除了一个分量外, 其余分量都等于真币的重量 `c`. 由于我们假定天平两边硬币数目相同, `bm A` 的每一行系数之和等于 `0`, 从而我们可将 `bm x` 的每个分量都减去 `c`, 得到向量 `bm y`, 它的 `n-1` 个分量等于 0, 剩下的一个分量可能取值为 `1, -1, 0`.
  2. 在方程 `bm A bm y = bm b` 中, `bm A` 称为称量矩阵, `bm b` 称为结果向量. 我们的目标是求出硬币与真币的偏差向量 `bm y`, 它一共可能有 `2n+1` 种情况: 为了能区分所有 `2n+1` 种情况, `bm A` 必须满足: 构成了一个合适的称量矩阵应该满足的所有条件.
  3. 计算可知, `bm A` 的编码空间大小为 `3^m`, 扣除掉零向量与负向量, `m` 次称量理论上最多可以从 `n = (3^m-1)//2` 枚硬币中找到假币并确定其轻重. 然而称量矩阵还应满足其它约束, 所以理论值还要更小一些. 比如, 3 次称量最多可以处理 12 枚硬币而不是 13 枚. 为找到称量矩阵, 你可以先列出所有可能的 `(3^m-1)//2` 个列向量, 丢弃掉多余的向量, 再给合适的列乘上 `-1`, 来保证每行系数和为 `0`. 下面是一个合适的称量矩阵 (不唯一):
    1 0  0 1  1 1 -1  0  0 -1 -1 -1
    0 1  0 1 -1 0  0 -1 -1 -1  1  1
    0 0 -1 0  0 1  1 -1  1 -1  1 -1
    
    于是称量方案为: 如果三次称量结果分别是左边重, 右边重和天平平衡, 那么 `bm b = (-1, 1, 0)^(sf T)`, 它等于称量矩阵的第 5 列取负. 这就说明 5 号硬币偏轻.

称巧克力 一条巧克力的标准重量是 30 g, 每盒有 12 条巧克力. 现在生产了 10 盒巧克力, 已知其中一盒的每条巧克力是 31 g, 而其它 9 盒符合标准. 只允许使用电子秤称一次, 问如何找出这盒超重的巧克力?

    约瑟夫问题 [葛立恒,高德纳《具体数学》] 一群人按 `1` 到 `n` 编号, 围成一圈. 从 `m` 号开始, 每 `m` 人淘汰一人, 记最后一个幸存者的编号为 `J(n, m)`.
  1. 求 `J(n, 2)`;
  2. 设 `m = 2`, 求倒数第二个被淘汰者的编号 `J_2(n, 2)`.
  3. 求 `J(n, m)`;
  1. 先设总人数为偶数. 在第一轮中, 所有编号为偶数的人被淘汰. 此时的局面与开始类似, 但人数减半, 且所有人的编号都由 `k` 变为 `2k-1`. 也就是说, `J(2n, 2) = 2 J(n, 2) - 1`. 再考虑总人数为奇数. 在第一轮中, 所有编号为偶数的人被淘汰, 接着 `1` 号也被淘汰, `3` 号排在首位. 此时的局面与开始类似, 但人数减半 (向下取整), 且所有人的编号由 `k` 变为 `2k+1`, 也就是说, `J(2n+1, 2) = 2 J(n, 2) + 1`. 下证 `J(2^n + k, 2) = 2k+1`, `quad 0 le k lt 2^n`. 首先由 `J(1, 2) = 1` 和递推 `J(2n, 2) = 2 J(n, 2) - 1` 得到: `J(2^n, 2) = 1`. 这指出人数为 `2` 的幂时 `1` 号为幸存者. 现在设人数为 `2^n+k`. 经过 `k` 次淘汰后, 排在第一位的人编号是 `2k+1`, 因此他就是最后的幸存者.
  2. `J_2` 的递推关系与 `J` 完全相同, 但初值条件变为 `J_2(2, 2) = 2` 和 `J_2(3, 2) = 1`. 于是 `J_2(2 * 2^n + k, 2) = 2^n+2k+1`,
    `J_2(3 * 2^n + k, 2) = 2k+1`,
    `0 le k lt 2^n`.

  3. 注1: 一段模拟程序
    // 返回约瑟夫游戏的 [幸存者, 倒数第二个被淘汰者]
    var j = (n, m=2) => {
        a = [...Array(n).keys().map(v => v+1)]
        let i = m-1
        while (a.length > 2) {
            i %= a.length
            a.splice(i, 1)
            i += m-1
        }
        return i % 2 ? a : a.reverse()
    }
    
    j(100) // [73, 9]
    
    注2: 考虑总人数 `N` 的二进制表示, 公式 `J(2^n + k, 2) = 2k+1`, `quad 0 le k lt 2^n` 表明, `J(N, 2)` 正好是 `N` 的向左循环移位的结果.

能放入 10 枚硬币的正方形的最小边长?

货架问题 [P&KU群群友@Lazy_Labs] 某商店只售卖一种货物. 第一天开始时刻, 店里有若干货架, 每个货架上恰有一件货物. 货物由店主分配给顾客, 顾客不能自主选择. 当某个货架上的货物卖完时, 就撤掉这个货架. 补货员会保证在第 `k` 天开始时刻, 每个未被撤掉的货架上有 `k` 件货物. 如果商店无货可卖就要关门. 现在假设你是店主, 为了保证商店不关门且每天都恰好卖出 `n` 件货物, 问第一天开始时店里至少要有多少货架?

设第 `k` 天开始时刻, 商店里至少需要 `x_k` 个货架. 当天卖出 `n` 件货物后, 撤掉空货架, 剩下的货架应大于等于下一天需要的数量, 于是 `k x_k - n ge x_(k+1)`. `x_k` 取满足上式的最小整数即可, 即: `x_k = ceil((x_(k+1)+n)/k)`,
`x_(n+1) = 1`.
接下来求解递推式, 先考虑连续情形: `y_k = (y_(k+1)+n)/k`,
`y_(n+1) = 1`.
两边同除以 `(k-1)!` 得到 `y_k/(k-1)! = y_(k+1)/k! + n/k!`, 于是 `y_k/(k-1)! = y_(n+1)/n! + n sum_(i=k)^n 1/i!`. 回到离散的情况, 我们猜想 `x_k = ceil(y_k)`, 并归纳证明: 从递推式容易看出 `x_k ge y_k`, 因此只需证 `x_k lt y_k+1`, 即证 `ceil((x_(k+1)+n)/k) lt (y_(k+1)+n)/k + 1`. 注意上式左边里面是 `1//k` 的整数倍, 再利用归纳假设 `x_(k+1) lt y_(k+1)+1` 就有 `"LHS" le (x_(k+1)+n)/k+(k-1)/k` `lt (y_(k+1)+n)/k + 1` `= "RHS"`. 于是 `x_k = ceil(y_k)`, 最终答案为 `x_1 = ceil(y_1)` `= ceil(1/n! + n sum_(i=1)^n 1/i!)`.
注: 运用两边夹取极限可知 `lim_(n to oo) x_1//n = "e"-1`.
公平组合游戏与 SG 函数 [CCBC1314《奇怪的游戏》, OI Wiki] 以下都是公平组合游戏的例子:
  1. Nim 游戏 有 n 堆石子, 两名玩家轮流取走任意一堆中的任意多 (≥ 1) 枚石子, 取走最后一枚石子的玩家获胜.
  2. 雨露均沾 有 n 堆石子, 两名玩家轮流操作, 每一回合可以取走一整堆石子, 或从每一堆石子中各取一枚, 取走最后一枚石子的玩家获胜.
  3. 整除游戏 (或一般的偏序游戏) 两名玩家轮流在 2 到 n 中选取整数, 每选一个数字, 就把这个数字及其所有倍数删除, 选走最后一个数字的玩家获胜.
  4. 儿时的游戏 初始时两名玩家各有 2 个数字 "1". 玩家轮流操作, 每一回合可以将对方的某个数字加到自己的某个数字上. 一旦自己的某个数字 ≥ 10, 就消掉这个数字. 先消掉手中所有数字的玩家获胜.
公平组合游戏具有以下特点:
  1. 局面变化可以用博弈图来描述. 其中每个节点代表游戏的一个状态, 如果状态 B 是 A 的后继状态, 就在 AB 之间连一条边. 这张图是有向无环图, 即状态不会出现循环. 例如 Nim 游戏中石子数量是严格减少的.
  2. 在每个状态下, 要么先手有必胜策略, 要么后手有必胜策略, 分别称为必胜状态和必败状态. 在公平组合游戏中, 没有后继的状态是必败状态. 一般地, 一个状态是必胜状态, 当且仅当存在一个后继是必败状态. 利用这一准则, 我们可以通过遍历状态图来判定游戏的胜负.
  3. 有些游戏 (如 Nim 游戏) 可以分解为多个独立子游戏. 玩家每回合只能在一个子游戏中移动一步, 如果在所有子游戏中都无法移动, 则游戏结束. 这些子游戏是相互独立的, 意味在一个子游戏中的移动不会改变其它子游戏的状态.
定义
  1. 正常规则的有限公平组合游戏, 简称游戏 定义为一张有向无环图, 附加一个初始状态: `G := (V, E, v_0)`.
  2. 两个游戏的和定义为 `G + H = (V, E, v_0)`, 其中顶点集是两个顶点集的笛卡尔积 `V := V_G xx V_H`. 边集定义为 `E := {((g_1, h_1), (g_2, h_2)): g_1 = g_2 and (h_1, h_2) in E_H or h_1 = h_2 and (g_1, g_2) in E_G}`. 即两个状态之间有边, 当且仅当其中一个状态分量相同, 而另一个分量之间有边. 初始状态定义为 `v_0 = (v_(0 G), v_(0 H))`. 可以看出 `G, H` 正是 `G + H` 的子游戏.
  3. 游戏的等价 给定两个游戏 `G_1, G_2`, 如果对任意游戏 `H`, 游戏 `G_1 + H` 和 `G_2 + H` 都同处于必胜状态或必败状态, 则称 `G_1, G_2` 等价, 记作 `G_1 ~~ G_2`. 可以验证这是一个等价关系.
推论
  1. 对任意游戏 `G` 和任意必败游戏 `Z`, 都有 `G ~~ G + Z`.
  2. 两个游戏 `G ~~ H` 当且仅当 `G + H` 是必败游戏.
  3. 所有必败游戏都等价.
  4. 任意游戏 `G` 都等价于某个单堆 Nim 游戏.
SG 函数
设游戏 `G` 等价于石子数为 `n` 的单堆 Nim 游戏, 我们记 `SG(G) = n`, 称为游戏 `G` 的 SG 函数 (Sprague-Grundy 函数). 注意游戏的定义中带有初始状态 `v_0`, 随着游戏进行, 状态在发生变化, 游戏也转化为另一个游戏了; 此时 SG 函数值也随之变化. 由于单堆 Nim 游戏必败, 当且仅当 `n = 0`. 我们得到判定游戏胜负的另一准则: 一个游戏 `G` 是必败的, 当且仅当 `SG(G) = 0`. 具体计算时, 如果一个游戏可以分解为子游戏 (像多堆 Nim 游戏那样), 则该游戏的 SG 函数值等于子游戏的 SG 函数值的异或: `SG(G + H) = SG(G) o+ SG(H)`. 对于单个游戏, 它的 SG 函数值是所有后继状态的 SG 函数值的 mex 值: `SG(G) = "mex"{SG(H): H 是 G 的后继}`. 其中 `"mex"(A) := min{n in NN_(ge 0): n !in A}`, 即 `A` 中未出现的最小自然数. 然而该公式的复杂度仍是指数级的.

说明: 计算整除游戏的必胜策略. 输入当前状态 (场上所有数字), 输出 "必胜" 或 "必败". 如果当前状态是必胜, 则再输出一个必败的后继状态供参考.