El pueblo unido jamas serà vencido!

特殊情况下的一类约瑟夫问题

不知道约瑟夫问题点这里

题干

数据全是随机生成的,显然可以暴力日过去。

\(\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

显然没什么规律。

但是看到题目的递推标签了吗?

我们得到归纳法的基础。(众所周知归纳法有基础和归纳两部分,不会的自己去学)

\[\large J(1) = 1 \]

\(\alpha.\)

假设现在有 \(2n\) 人,对于第一轮:

出局的人编号为:\(2,4,6,8,\cdots ,2n\) 总计\(n\)人。

剩下的人编号为:\(1,3,5,7,\cdots,2n - 1\),总计\(n\)人。

现在任意的 \(J(2n)\) 情况等价于 \(J(n)\) 的情况。

考虑重编号:

\[\large \begin{aligned} & 1,3,5,7,\cdots,2n - 1\\ &1,2,3,4,\cdots,n \end{aligned} \]

很像一次函数的关系,拟合计算可得

\(y = 2x-1\) 这样一个关系式。

于是可知\(J(n)\)的结果就是\(J(2n)\)一轮后重编号的结果

于是

\[\large J(2n) = 2J(n) - 1,n \ge 1 \]

\(\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)\) 的情况。

于是

\[\large J(2n + 1) = 2J(n) + 1,n \ge 1 \]

综上,递推式为

\[\large \boxed{ \begin{aligned} &J(1) = 1\\ &J(2n) = 2J(n) - 1,n \ge 1\\ &J(2n + 1) = 2J(n) + 1,n \ge 1 \end{aligned} } \]

封闭形式

众所周知给你递推式就是用来解的,管你用什么方法。

显然第一次打表格局小了,现在按照 \(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)\)

\[\large J(2^m + l) = 2l + 1 \]

证明

基础:

\(m = 0,l = 0\) 时,\(J(2^0 + 0) = J(1) = 1\)

归纳:

\(l = 0\) 时,\(J(n) = J(2^m + l) = J(2 ^ m) = 1\)

\[\large \begin{aligned} J(2^m) & = 2J(2^{m - 1} - 1) - 1\\ & = 2^2J(2^{m - 2}) - 3\\ & = 2^3J(2^{m - 3}) - 7\\ & = 2^mJ(1) - 2^m + 1 \end{aligned} \]

对于 \(2^m + l\) 为偶数时,

\[\large \begin{aligned} J(2^m + l) & = 2J(2 ^ {m - 1} + \frac{l}{2}) - 1\\ & = 2(\frac{2l}{2} + 1) - 1\\ & = 2l + 1 \end{aligned} \]

\[\large \begin{aligned} \alpha.J(2n) &= 2J(n) - 1\\ \beta.J(2n + 1) &= 2J(n) + 1 \end{aligned} \]

\(\alpha - \beta\)

\(J(2n + 1) - J(2n) = 2\)

于是对于奇数和偶数的 \(n\)

总是有:

\[\large \boxed{ \begin{aligned} m \ge 0,l \in [0,2^m) \\ J(2^m + l) = 2l + 1 \end{aligned} } \]

然后使用跑得飞快的 __builtin_clz() 就能求 $\log $ 了。

posted @ 2022-01-26 16:17  AstatineAi  阅读(38)  评论(0编辑  收藏  举报