特殊情况下的一类约瑟夫问题
数据全是随机生成的,显然可以暴力日过去。
\(\mathrm{O}(\log n)\) 递归做法
from OI-wiki
考虑到我们每次走 \(k\) 个删一个,那么在一圈以内我们可以删掉 \(\lfloor \frac{n}{k} \rfloor\) 个,然后剩下了\(n - \lfloor \frac{n}{k} \rfloor\) 个人。这时我们在第 \(\lfloor \frac{n}{k} \rfloor \times k\) 个人的位置上。而你发现这个东西它等于 \(n - n \mod k\) 。于是我们继续递归处理,算完后还原它的相对位置。
int josephus(int n, int k) {
if (n == 1) return 0;
if (k == 1) return n - 1;
if (k > n) return (josephus(n - 1, k) + k) % n;
int res = josephus(n - n / k, k);
res -= n % k;
if (res < 0)
res += n;
else
res += res / (k - 1);
return res;
}
正解
定义 \(J(n)\) 表示人数为 \(n\) 时幸存的编号。
先打个表
\(n\) | 1 | 2 | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|---|
\(J(n)\) | 1 | 1 | 3 | 1 | 3 | 5 |
显然没什么规律。
但是看到题目的递推标签了吗?
我们得到归纳法的基础。(众所周知归纳法有基础和归纳两部分,不会的自己去学)
\(\alpha.\)
假设现在有 \(2n\) 人,对于第一轮:
出局的人编号为:\(2,4,6,8,\cdots ,2n\) 总计\(n\)人。
剩下的人编号为:\(1,3,5,7,\cdots,2n - 1\),总计\(n\)人。
现在任意的 \(J(2n)\) 情况等价于 \(J(n)\) 的情况。
考虑重编号:
很像一次函数的关系,拟合计算可得
\(y = 2x-1\) 这样一个关系式。
于是可知\(J(n)\)的结果就是\(J(2n)\)一轮后重编号的结果
于是
\(\beta.\)
假设现在有\(2n+1\)人,第二轮淘汰开始时正好把1号淘汰。
出局的人编号为:\(2,4,6,8,\cdots ,2n,1\)
剩下的人编号为:\(3,5,7,,9\cdots,2n + 1\)
可得关系式 \(y = 2x + 1\)
现在任意的 \(J(2n + 1)\) 情况等价于 \(J(n)\) 的情况。
于是
综上,递推式为
封闭形式
众所周知给你递推式就是用来解的,管你用什么方法。
显然第一次打表格局小了,现在按照 \(2\) 的幂来分一下块。
\(2^0\) | \(n\) | 1 | |||||
---|---|---|---|---|---|---|---|
\(2^0\) | \(J(n)\) | 1 | |||||
\(2^1\) | \(n\) | 2 | 3 | ||||
\(2^1\) | \(J(n)\) | 1 | 3 | ||||
\(2^2\) | \(n\) | 4 | 5 | 6 | 7 | ||
\(2^2\) | \(J(n)\) | 1 | 3 | 5 | 7 | ||
\(2^3\) | \(n\) | 8 | 9 | 10 | 11 | 12 | 13 |
\(2^3\) | \(J(n)\) | 1 | 3 | 5 | 7 | 9 | 11 |
显然对于每一组内都有 \(f(t) = 2t + 1\)
定义 \(m \ge 0,l \in [0,2^m)\)
有
证明
基础:
\(m = 0,l = 0\) 时,\(J(2^0 + 0) = J(1) = 1\)
归纳:
\(l = 0\) 时,\(J(n) = J(2^m + l) = J(2 ^ m) = 1\)
对于 \(2^m + l\) 为偶数时,
由
\(\alpha - \beta\) 得
\(J(2n + 1) - J(2n) = 2\)
于是对于奇数和偶数的 \(n\)
总是有:
然后使用跑得飞快的 __builtin_clz()
就能求 $\log $ 了。