约瑟夫问题小结
前前后后做过三道关于约瑟夫问题的题了。然而今天这次考试让我认识到其实我并没有完全理解约瑟夫问题的解法。
今天花了大概一个多小时的时间彻底弄明白了(可能是我太垃圾,用的时间还是太长了),以后如果再考约瑟夫应该不会挂了吧。。。
约瑟夫游戏(题目大意:经典约瑟夫问题,要求输出出圈顺序,数据范围$30000$)
这道题目是初学OI那段时间写的??码风还没成型。$O(n^2)$暴扫即可。
约瑟夫问题二(题目大意:经典约瑟夫问题,要求输出获胜者编号,数据范围$1e8$)
我们将一个还剩下$n$个人的约瑟夫问题成为一个n阶问题。
对于一个n阶问题,我们给所有成员依次编号为$0,1,2...n-1$,
即$0$号要报$"1"$,$1$号要报$"2"$,以此类推,本轮游戏的出局者一定是编号为$(m-1)%n$的人。
从$n$阶问题到$n-1$阶问题,部分人的编号将发生改变。根据命名规则,编号为$(m-1)%n+1$的人将被命名为$0$。
此时设第$i$个人在$n-1$阶问题中的编号为$f_i$,在n阶问题中的编号为$g_i$,则可由$f_i$推得$g_i$:$g_i=(f_i+m)%n$。
解释:如右图:对于每一阶问题中,一个人的编号还可以表示在他前面报数的人数。对于$n-1$阶问题,$i$的前面有$f_i$个人。本阶问题的$0$号在上一阶问题中一定在出局者后面。我们假设$n$足够大。则本阶的$0$号在上一阶前面一定有$m$个人。此时,$g_i=(f_i+m)%n$。模$n$意义下同理。
此时我们得到了由$n-1$阶问题推向$n$阶问题的一般公式。而我们还知道,在第1阶问题的幸存者必定被编号为$0$。于是我们就可以$O(n)$推导出这名幸存者在第一轮,即第$n$阶问题中的编号是多少,此时即为所求答案。
One(题目大意:约瑟夫问题改编版:第i轮报"i"者出局,求获胜者编号,数据范围$1e7$)
第i轮报"i"者出局,将式子$g_i=(f_i+m)$中的$m$替换为$n-i+1$即可。
嘟嘟噜(题目大意:经典约瑟夫问题,数据范围$n \leqslant 1e9,m \leqslant 1e5$)
数据范围$1e9$,$O(n)$递推会$T$掉。考虑加速我们刚才的过程。观察数据范围可以发现,$m$远小于$n$。
此时的倒序推导过程可以跳步实现。对于一个$i$阶问题,$i$远大于$m$时,可以直接跳到第$i+k$轮求解。
$k=min((i-1-ans)/m+1,n-i+1)$(在这个式子中我们取剩下$i-1$个人为第i轮翻转)
解释:$i-1$为边界。(这里我们没有必要预估跳了$k$步后的边界。对于当前边界求解即可。)$ans$为当前幸存者的编号。
$i-1-ans$是边界到$ans$的距离,除以m即为出局位置移动到边界所需步数。$+1$为翻过边界进入下一层的那一步。
$i$也是轮数,$n-i+1$为我还需要的轮数。(肯定不能还原到$n+1$个人的时候吧……)
时间复杂度……大概接近$O(mlogn)$??